mirror of https://github.com/oxen-io/lokinet
commit
5769e5c716
@ -0,0 +1 @@
|
||||
#include <crypto/mock_crypto.hpp>
|
@ -0,0 +1,76 @@
|
||||
#ifndef TEST_LLARP_CRYPTO_MOCK_CRYPTO
|
||||
#define TEST_LLARP_CRYPTO_MOCK_CRYPTO
|
||||
|
||||
#include <crypto/crypto.hpp>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
struct MockCrypto final : public Crypto
|
||||
{
|
||||
MOCK_METHOD3(xchacha20,
|
||||
bool(const llarp_buffer_t &, const SharedSecret &,
|
||||
const TunnelNonce &));
|
||||
|
||||
MOCK_METHOD4(xchacha20_alt,
|
||||
bool(const llarp_buffer_t &, const llarp_buffer_t &,
|
||||
const SharedSecret &, const byte_t *));
|
||||
|
||||
MOCK_METHOD4(dh_client,
|
||||
bool(SharedSecret &, const PubKey &, const SecretKey &,
|
||||
const TunnelNonce &));
|
||||
|
||||
MOCK_METHOD4(dh_server,
|
||||
bool(SharedSecret &, const PubKey &, const SecretKey &,
|
||||
const TunnelNonce &));
|
||||
|
||||
MOCK_METHOD4(transport_dh_client,
|
||||
bool(SharedSecret &, const PubKey &, const SecretKey &,
|
||||
const TunnelNonce &));
|
||||
|
||||
MOCK_METHOD4(transport_dh_server,
|
||||
bool(SharedSecret &, const PubKey &, const SecretKey &,
|
||||
const TunnelNonce &));
|
||||
|
||||
MOCK_METHOD2(hash, bool(byte_t *, const llarp_buffer_t &));
|
||||
|
||||
MOCK_METHOD2(shorthash, bool(ShortHash &, const llarp_buffer_t &));
|
||||
|
||||
MOCK_METHOD3(hmac,
|
||||
bool(byte_t *, const llarp_buffer_t &,
|
||||
const SharedSecret &));
|
||||
|
||||
MOCK_METHOD3(sign,
|
||||
bool(Signature &, const SecretKey &,
|
||||
const llarp_buffer_t &));
|
||||
|
||||
MOCK_METHOD3(verify,
|
||||
bool(const PubKey &, const llarp_buffer_t &,
|
||||
const Signature &));
|
||||
|
||||
MOCK_METHOD2(seed_to_secretkey,
|
||||
bool(llarp::SecretKey &, const llarp::IdentitySecret &));
|
||||
|
||||
MOCK_METHOD1(randomize, void(const llarp_buffer_t &));
|
||||
|
||||
MOCK_METHOD2(randbytes, void(void *, size_t));
|
||||
|
||||
MOCK_METHOD1(identity_keygen, void(SecretKey &));
|
||||
|
||||
MOCK_METHOD1(encryption_keygen, void(SecretKey &));
|
||||
|
||||
MOCK_METHOD1(pqe_keygen, void(PQKeyPair &));
|
||||
|
||||
MOCK_METHOD3(pqe_decrypt,
|
||||
bool(const PQCipherBlock &, SharedSecret &, const byte_t *));
|
||||
|
||||
MOCK_METHOD3(pqe_encrypt,
|
||||
bool(PQCipherBlock &, SharedSecret &, const PQPubKey &));
|
||||
};
|
||||
} // namespace test
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,117 @@
|
||||
#include <dht/node.hpp>
|
||||
|
||||
#include <test_util.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using namespace llarp;
|
||||
using namespace ::testing;
|
||||
|
||||
using test::makeBuf;
|
||||
|
||||
struct TestDhtRCNode : public ::testing::Test
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(TestDhtRCNode, construct)
|
||||
{
|
||||
dht::RCNode node;
|
||||
ASSERT_THAT(node.ID, Property(&dht::Key_t::IsZero, true));
|
||||
|
||||
node.ID.Fill(0xCA);
|
||||
node.rc.last_updated = 101;
|
||||
|
||||
dht::RCNode other{node};
|
||||
ASSERT_EQ(node.ID, other.ID);
|
||||
ASSERT_EQ(node.rc, other.rc);
|
||||
|
||||
RouterContact contact;
|
||||
contact.pubkey.Randomize();
|
||||
|
||||
dht::RCNode fromContact{contact};
|
||||
ASSERT_EQ(fromContact.ID.as_array(), contact.pubkey.as_array());
|
||||
}
|
||||
|
||||
TEST_F(TestDhtRCNode, lt)
|
||||
{
|
||||
dht::RCNode one;
|
||||
dht::RCNode two;
|
||||
dht::RCNode three;
|
||||
dht::RCNode eqThree;
|
||||
|
||||
one.rc.last_updated = 1;
|
||||
two.rc.last_updated = 2;
|
||||
three.rc.last_updated = 3;
|
||||
eqThree.rc.last_updated = 3;
|
||||
|
||||
// LT cases
|
||||
ASSERT_THAT(one, Lt(two));
|
||||
ASSERT_THAT(one, Lt(three));
|
||||
ASSERT_THAT(one, Lt(eqThree));
|
||||
ASSERT_THAT(two, Lt(three));
|
||||
ASSERT_THAT(two, Lt(eqThree));
|
||||
|
||||
// !LT cases
|
||||
ASSERT_THAT(one, Not(Lt(one)));
|
||||
ASSERT_THAT(two, Not(Lt(one)));
|
||||
ASSERT_THAT(two, Not(Lt(two)));
|
||||
ASSERT_THAT(three, Not(Lt(one)));
|
||||
ASSERT_THAT(three, Not(Lt(two)));
|
||||
ASSERT_THAT(three, Not(Lt(three)));
|
||||
ASSERT_THAT(three, Not(Lt(eqThree)));
|
||||
}
|
||||
|
||||
struct TestDhtISNode : public ::testing::Test
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(TestDhtISNode, construct)
|
||||
{
|
||||
dht::ISNode node;
|
||||
ASSERT_THAT(node.ID, Property(&dht::Key_t::IsZero, true));
|
||||
|
||||
node.ID.Fill(0xCA);
|
||||
node.introset.K.Fill(0xDB);
|
||||
|
||||
dht::ISNode other{node};
|
||||
ASSERT_EQ(node.ID, other.ID);
|
||||
ASSERT_EQ(node.introset, other.introset);
|
||||
|
||||
service::IntroSet introSet;
|
||||
introSet.K.Randomize();
|
||||
introSet.A.UpdateAddr();
|
||||
|
||||
dht::ISNode fromIntro{introSet};
|
||||
|
||||
ASSERT_EQ(fromIntro.ID.as_array(), introSet.A.Addr().as_array());
|
||||
}
|
||||
|
||||
TEST_F(TestDhtISNode, lt)
|
||||
{
|
||||
dht::ISNode one;
|
||||
dht::ISNode two;
|
||||
dht::ISNode three;
|
||||
dht::ISNode eqThree;
|
||||
|
||||
one.introset.T = 1;
|
||||
two.introset.T = 2;
|
||||
three.introset.T = 3;
|
||||
eqThree.introset.T = 3;
|
||||
|
||||
// LT cases
|
||||
ASSERT_THAT(one, Lt(two));
|
||||
ASSERT_THAT(one, Lt(three));
|
||||
ASSERT_THAT(one, Lt(eqThree));
|
||||
ASSERT_THAT(two, Lt(three));
|
||||
ASSERT_THAT(two, Lt(eqThree));
|
||||
|
||||
// !LT cases
|
||||
ASSERT_THAT(one, Not(Lt(one)));
|
||||
ASSERT_THAT(two, Not(Lt(one)));
|
||||
ASSERT_THAT(two, Not(Lt(two)));
|
||||
ASSERT_THAT(three, Not(Lt(one)));
|
||||
ASSERT_THAT(three, Not(Lt(two)));
|
||||
ASSERT_THAT(three, Not(Lt(three)));
|
||||
ASSERT_THAT(three, Not(Lt(eqThree)));
|
||||
}
|
@ -0,0 +1,222 @@
|
||||
#include <dht/serviceaddresslookup.hpp>
|
||||
|
||||
#include <crypto/mock_crypto.hpp>
|
||||
#include <dht/mock_context.hpp>
|
||||
#include <dht/messages/gotintro.hpp>
|
||||
#include <service/IntroSet.hpp>
|
||||
#include <test_util.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using namespace llarp;
|
||||
using namespace ::testing;
|
||||
|
||||
using test::makeBuf;
|
||||
|
||||
struct MockIntroSetHandler
|
||||
{
|
||||
MOCK_METHOD1(call, void(const std::vector< service::IntroSet > &));
|
||||
};
|
||||
|
||||
static constexpr uint64_t EXPIRY = 1548503831ull;
|
||||
|
||||
struct TestDhtServiceAddressLookup : public ::testing::Test
|
||||
{
|
||||
test::MockCrypto crypto;
|
||||
MockIntroSetHandler introsetHandler;
|
||||
|
||||
dht::Key_t ourKey;
|
||||
dht::Key_t txKey;
|
||||
uint64_t txId;
|
||||
dht::TXOwner txOwner;
|
||||
service::Address address;
|
||||
|
||||
test::MockContext context;
|
||||
uint64_t r;
|
||||
std::unique_ptr< dht::ServiceAddressLookup > serviceAddressLookup;
|
||||
|
||||
TestDhtServiceAddressLookup()
|
||||
: ourKey(makeBuf< dht::Key_t >(0xFF))
|
||||
, txKey(makeBuf< dht::Key_t >(0x01))
|
||||
, txId(2)
|
||||
, txOwner(txKey, txId)
|
||||
, address(makeBuf< service::Address >(0x03))
|
||||
, r(4)
|
||||
{
|
||||
EXPECT_CALL(context, OurKey()).WillOnce(ReturnRef(ourKey));
|
||||
|
||||
serviceAddressLookup = std::make_unique< dht::ServiceAddressLookup >(
|
||||
txOwner, address, &context, r,
|
||||
std::bind(&MockIntroSetHandler::call, &introsetHandler,
|
||||
std::placeholders::_1));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestDhtServiceAddressLookup, validate)
|
||||
{
|
||||
// Concerns
|
||||
// - introset fails to verify
|
||||
// - introset topic is not the target
|
||||
// - happy path
|
||||
|
||||
{
|
||||
service::IntroSet introset;
|
||||
EXPECT_CALL(context, Crypto()).WillOnce(Return(&crypto));
|
||||
EXPECT_CALL(context, Now()).WillOnce(Return(EXPIRY));
|
||||
EXPECT_CALL(crypto, verify(_, _, _)).WillOnce(Return(false));
|
||||
|
||||
ASSERT_FALSE(serviceAddressLookup->Validate(introset));
|
||||
}
|
||||
|
||||
{
|
||||
service::IntroSet introset;
|
||||
|
||||
// Fiddle with the introset so we pass the Verify call
|
||||
introset.I.emplace_back();
|
||||
introset.I.front().expiresAt =
|
||||
EXPIRY + service::MAX_INTROSET_TIME_DELTA + 1;
|
||||
|
||||
// Set expectations
|
||||
EXPECT_CALL(context, Crypto()).WillOnce(Return(&crypto));
|
||||
EXPECT_CALL(context, Now()).WillOnce(Return(EXPIRY));
|
||||
EXPECT_CALL(crypto, verify(_, _, _)).WillOnce(Return(true));
|
||||
|
||||
ASSERT_FALSE(serviceAddressLookup->Validate(introset));
|
||||
}
|
||||
|
||||
{
|
||||
service::IntroSet introset;
|
||||
// Set the current address of the lookup to be equal to the default address.
|
||||
// This is easier than manipulating the ServiceInfo address.
|
||||
serviceAddressLookup->target.Zero();
|
||||
|
||||
// Fiddle with the introset so we pass the Verify call
|
||||
introset.I.emplace_back();
|
||||
introset.I.front().expiresAt =
|
||||
EXPIRY + service::MAX_INTROSET_TIME_DELTA + 1;
|
||||
|
||||
// Set expectations
|
||||
EXPECT_CALL(context, Crypto()).WillOnce(Return(&crypto));
|
||||
EXPECT_CALL(context, Now()).WillOnce(Return(EXPIRY));
|
||||
EXPECT_CALL(crypto, verify(_, _, _)).WillOnce(Return(true));
|
||||
|
||||
ASSERT_TRUE(serviceAddressLookup->Validate(introset));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestDhtServiceAddressLookup, start)
|
||||
{
|
||||
// Verify input arguments are passed correctly.
|
||||
// The actual logic is inside the `dht::AbstractContext` implementation.
|
||||
|
||||
// clang-format off
|
||||
EXPECT_CALL(context, DHTSendTo(
|
||||
Eq(txKey.as_array()),
|
||||
WhenDynamicCastTo< dht::FindIntroMessage* >(NotNull()),
|
||||
true)
|
||||
).Times(1);
|
||||
// clang-format off
|
||||
|
||||
ASSERT_NO_THROW(serviceAddressLookup->Start(txOwner));
|
||||
}
|
||||
|
||||
TEST_F(TestDhtServiceAddressLookup, get_next_peer)
|
||||
{
|
||||
// Concerns
|
||||
// - Nodes returns nullptr
|
||||
// - Happy path
|
||||
|
||||
dht::Key_t key = makeBuf< dht::Key_t >(0x02);
|
||||
std::set< dht::Key_t > exclude;
|
||||
{
|
||||
EXPECT_CALL(context, Nodes()).WillOnce(ReturnNull());
|
||||
ASSERT_FALSE(serviceAddressLookup->GetNextPeer(key, exclude));
|
||||
}
|
||||
|
||||
{
|
||||
uint64_t randVal = 0;
|
||||
|
||||
dht::Bucket< dht::RCNode > nodes(ourKey, [&]() { return randVal++; });
|
||||
nodes.nodes.emplace(makeBuf< dht::Key_t >(0x03), dht::RCNode());
|
||||
EXPECT_CALL(context, Nodes()).WillOnce(Return(&nodes));
|
||||
ASSERT_TRUE(serviceAddressLookup->GetNextPeer(key, exclude));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestDhtServiceAddressLookup, do_next)
|
||||
{
|
||||
// Concerns:
|
||||
// - R != 0
|
||||
// - R = 0
|
||||
|
||||
const dht::Key_t key = makeBuf< dht::Key_t >(0x02);
|
||||
|
||||
{
|
||||
// R != 0
|
||||
EXPECT_CALL(context, LookupIntroSetRecursive(address, txKey, txId, key, r - 1, _));
|
||||
ASSERT_NO_THROW(serviceAddressLookup->DoNextRequest(key));
|
||||
}
|
||||
|
||||
{
|
||||
// R = 0
|
||||
serviceAddressLookup->R = 0;
|
||||
EXPECT_CALL(context, LookupIntroSetIterative(address, txKey, txId, key, _));
|
||||
ASSERT_NO_THROW(serviceAddressLookup->DoNextRequest(key));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestDhtServiceAddressLookup, send_reply)
|
||||
{
|
||||
// Concerns
|
||||
// - handle result is set, is called
|
||||
// - handle result is not set
|
||||
|
||||
{
|
||||
serviceAddressLookup->valuesFound.emplace_back();
|
||||
EXPECT_CALL(introsetHandler, call(SizeIs(1)));
|
||||
|
||||
// clang-format off
|
||||
EXPECT_CALL(
|
||||
context,
|
||||
DHTSendTo(
|
||||
Eq(txKey.as_array()),
|
||||
WhenDynamicCastTo<dht::GotIntroMessage *>(
|
||||
AllOf(
|
||||
NotNull(),
|
||||
Field(&dht::GotIntroMessage::I, SizeIs(1))
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
ASSERT_NO_THROW(serviceAddressLookup->SendReply());
|
||||
}
|
||||
|
||||
{
|
||||
serviceAddressLookup->valuesFound.clear();
|
||||
serviceAddressLookup->valuesFound.emplace_back();
|
||||
serviceAddressLookup->handleResult =
|
||||
decltype(serviceAddressLookup->handleResult)();
|
||||
|
||||
// clang-format off
|
||||
EXPECT_CALL(
|
||||
context,
|
||||
DHTSendTo(
|
||||
Eq(txKey.as_array()),
|
||||
WhenDynamicCastTo<dht::GotIntroMessage *>(
|
||||
AllOf(
|
||||
NotNull(),
|
||||
Field(&dht::GotIntroMessage::I, SizeIs(1))
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
ASSERT_NO_THROW(serviceAddressLookup->SendReply());
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
#include <dht/taglookup.hpp>
|
||||
|
||||
#include <crypto/mock_crypto.hpp>
|
||||
#include <dht/mock_context.hpp>
|
||||
#include <dht/messages/gotintro.hpp>
|
||||
#include <service/IntroSet.hpp>
|
||||
#include <test_util.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace llarp;
|
||||
using namespace ::testing;
|
||||
|
||||
using test::makeBuf;
|
||||
|
||||
static constexpr uint64_t EXPIRY = 1548503831ull;
|
||||
|
||||
struct TestDhtTagLookup : public ::testing::Test
|
||||
{
|
||||
test::MockCrypto crypto;
|
||||
dht::Key_t txKey;
|
||||
uint64_t txId;
|
||||
dht::TXOwner txOwner;
|
||||
service::Tag tag;
|
||||
|
||||
test::MockContext context;
|
||||
uint64_t r;
|
||||
dht::TagLookup tagLookup;
|
||||
|
||||
TestDhtTagLookup()
|
||||
: txKey(makeBuf< dht::Key_t >(0x01))
|
||||
, txId(2)
|
||||
, txOwner(txKey, txId)
|
||||
, tag(makeBuf< service::Tag >(0x03))
|
||||
, r(4)
|
||||
, tagLookup(txOwner, tag, &context, r)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestDhtTagLookup, validate)
|
||||
{
|
||||
// Concerns
|
||||
// - introset fails to verify
|
||||
// - introset topic is not the target
|
||||
// - happy path
|
||||
|
||||
{
|
||||
service::IntroSet introset;
|
||||
EXPECT_CALL(context, Crypto()).WillOnce(Return(&crypto));
|
||||
EXPECT_CALL(context, Now()).WillOnce(Return(EXPIRY));
|
||||
EXPECT_CALL(crypto, verify(_, _, _)).WillOnce(Return(false));
|
||||
|
||||
ASSERT_FALSE(tagLookup.Validate(introset));
|
||||
}
|
||||
|
||||
{
|
||||
service::IntroSet introset;
|
||||
// Set topic to be different to the current tag
|
||||
introset.topic = makeBuf< service::Tag >(0x02);
|
||||
|
||||
// Fiddle with the introset so we pass the Verify call
|
||||
introset.I.emplace_back();
|
||||
introset.I.front().expiresAt =
|
||||
EXPIRY + service::MAX_INTROSET_TIME_DELTA + 1;
|
||||
|
||||
// Set expectations
|
||||
EXPECT_CALL(context, Crypto()).WillOnce(Return(&crypto));
|
||||
EXPECT_CALL(context, Now()).WillOnce(Return(EXPIRY));
|
||||
EXPECT_CALL(crypto, verify(_, _, _)).WillOnce(Return(true));
|
||||
|
||||
ASSERT_FALSE(tagLookup.Validate(introset));
|
||||
}
|
||||
|
||||
{
|
||||
service::IntroSet introset;
|
||||
// Set topic to be equal to the current tag
|
||||
introset.topic = tag;
|
||||
|
||||
// Fiddle with the introset so we pass the Verify call
|
||||
introset.I.emplace_back();
|
||||
introset.I.front().expiresAt =
|
||||
EXPIRY + service::MAX_INTROSET_TIME_DELTA + 1;
|
||||
|
||||
// Set expectations
|
||||
EXPECT_CALL(context, Crypto()).WillOnce(Return(&crypto));
|
||||
EXPECT_CALL(context, Now()).WillOnce(Return(EXPIRY));
|
||||
EXPECT_CALL(crypto, verify(_, _, _)).WillOnce(Return(true));
|
||||
|
||||
ASSERT_TRUE(tagLookup.Validate(introset));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestDhtTagLookup, start)
|
||||
{
|
||||
// Verify input arguments are passed correctly.
|
||||
// The actual logic is inside the `dht::AbstractContext` implementation.
|
||||
|
||||
// clang-format off
|
||||
EXPECT_CALL(context, DHTSendTo(
|
||||
Eq(txKey.as_array()),
|
||||
WhenDynamicCastTo< dht::FindIntroMessage* >(NotNull()),
|
||||
true)
|
||||
).Times(1);
|
||||
// clang-format off
|
||||
|
||||
ASSERT_NO_THROW(tagLookup.Start(txOwner));
|
||||
}
|
||||
|
||||
TEST_F(TestDhtTagLookup, get_next_peer)
|
||||
{
|
||||
dht::Key_t key = makeBuf< dht::Key_t >(0x02);
|
||||
std::set< dht::Key_t > exclude;
|
||||
ASSERT_FALSE(tagLookup.GetNextPeer(key, exclude));
|
||||
}
|
||||
|
||||
TEST_F(TestDhtTagLookup, do_next)
|
||||
{
|
||||
const dht::Key_t key = makeBuf< dht::Key_t >(0x02);
|
||||
ASSERT_NO_THROW(tagLookup.DoNextRequest(key));
|
||||
}
|
||||
|
||||
TEST_F(TestDhtTagLookup, send_reply)
|
||||
{
|
||||
// Concerns
|
||||
// - empty values found
|
||||
// - when found.size < 2
|
||||
// - FindRandomIntroSetsWithTagExcluding returns empty
|
||||
// - FindRandomIntroSetsWithTagExcluding result are added to call
|
||||
// - DHTSendTo called with correct params
|
||||
|
||||
{
|
||||
tagLookup.valuesFound.clear();
|
||||
// clang-format off
|
||||
EXPECT_CALL(context, FindRandomIntroSetsWithTagExcluding(tag, _, IsEmpty()))
|
||||
.WillOnce(Return(std::set< service::IntroSet >()));
|
||||
|
||||
EXPECT_CALL(
|
||||
context,
|
||||
DHTSendTo(
|
||||
Eq(txKey.as_array()),
|
||||
WhenDynamicCastTo<dht::GotIntroMessage *>(
|
||||
AllOf(
|
||||
NotNull(),
|
||||
Field(&dht::GotIntroMessage::I, IsEmpty())
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
// clang-format on
|
||||
ASSERT_NO_THROW(tagLookup.SendReply());
|
||||
}
|
||||
|
||||
{
|
||||
tagLookup.valuesFound.clear();
|
||||
std::set< service::IntroSet > results;
|
||||
results.emplace();
|
||||
// clang-format off
|
||||
EXPECT_CALL(context, FindRandomIntroSetsWithTagExcluding(tag, _, IsEmpty()))
|
||||
.WillOnce(Return(results));
|
||||
|
||||
EXPECT_CALL(
|
||||
context,
|
||||
DHTSendTo(
|
||||
Eq(txKey.as_array()),
|
||||
WhenDynamicCastTo<dht::GotIntroMessage *>(
|
||||
AllOf(
|
||||
NotNull(),
|
||||
Field(&dht::GotIntroMessage::I, SizeIs(1))
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
// clang-format on
|
||||
ASSERT_NO_THROW(tagLookup.SendReply());
|
||||
}
|
||||
|
||||
{
|
||||
// clang-format off
|
||||
tagLookup.valuesFound.clear();
|
||||
tagLookup.valuesFound.emplace_back();
|
||||
EXPECT_CALL(context, FindRandomIntroSetsWithTagExcluding(tag, _, SizeIs(1)))
|
||||
.WillOnce(Return(std::set< service::IntroSet >()));
|
||||
|
||||
EXPECT_CALL(
|
||||
context,
|
||||
DHTSendTo(
|
||||
Eq(txKey.as_array()),
|
||||
WhenDynamicCastTo<dht::GotIntroMessage *>(
|
||||
AllOf(
|
||||
NotNull(),
|
||||
Field(&dht::GotIntroMessage::I, SizeIs(1))
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
// clang-format on
|
||||
ASSERT_NO_THROW(tagLookup.SendReply());
|
||||
}
|
||||
|
||||
{
|
||||
tagLookup.valuesFound.clear();
|
||||
tagLookup.valuesFound.emplace_back();
|
||||
tagLookup.valuesFound.back().T = 1;
|
||||
tagLookup.valuesFound.emplace_back();
|
||||
tagLookup.valuesFound.back().T = 2;
|
||||
// clang-format off
|
||||
EXPECT_CALL(context, FindRandomIntroSetsWithTagExcluding(_, _, _)).Times(0);
|
||||
|
||||
EXPECT_CALL(
|
||||
context,
|
||||
DHTSendTo(
|
||||
Eq(txKey.as_array()),
|
||||
WhenDynamicCastTo<dht::GotIntroMessage *>(
|
||||
AllOf(
|
||||
NotNull(),
|
||||
Field(&dht::GotIntroMessage::I, SizeIs(2))
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
// clang-format on
|
||||
ASSERT_NO_THROW(tagLookup.SendReply());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue