test: Add some unit tests for important internal DHT functions.

We definitely need more of this kind of test so refactorings don't
accidentally break things in ways that happen to still work in auto
tests.
This commit is contained in:
iphydf 2021-11-30 18:15:27 +00:00
parent fd73f3eeb6
commit 57b0651ffd
No known key found for this signature in database
GPG Key ID: 3855DBA2D74403C9
5 changed files with 133 additions and 2 deletions

View File

@ -1,7 +1,7 @@
---
cirrus-ci_task:
container:
image: toxchat/toktok-stack:0.0.13
image: toxchat/toktok-stack:0.0.18
cpu: 2
memory: 2G
configure_script:
@ -22,7 +22,7 @@ cirrus-ci_task:
cimple_task:
container:
image: toxchat/toktok-stack:0.0.13
image: toxchat/toktok-stack:0.0.18
cpu: 2
memory: 4G
configure_script:

View File

@ -363,6 +363,7 @@ include(CompileGTest)
#
unit_test(toxav ring_buffer)
unit_test(toxav rtp)
unit_test(toxcore DHT)
unit_test(toxcore crypto_core)
unit_test(toxcore mono_time)
unit_test(toxcore ping_array)

View File

@ -153,6 +153,16 @@ cc_library(
],
)
cc_test(
name = "DHT_test",
size = "small",
srcs = ["DHT_test.cc"],
deps = [
":DHT",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "DHT_srcs",
hdrs = [

View File

@ -17,6 +17,10 @@
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Maximum number of clients stored per friend. */
#define MAX_FRIEND_CLIENTS 8
@ -405,4 +409,8 @@ bool dht_non_lan_connected(const DHT *dht);
uint32_t addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

112
toxcore/DHT_test.cc Normal file
View File

@ -0,0 +1,112 @@
#include "DHT.h"
#include <gtest/gtest.h>
#include <algorithm>
#include <array>
#include "crypto_core.h"
namespace {
using PublicKey = std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE>;
template <typename T, size_t N>
std::array<T, N> to_array(T const (&arr)[N]) {
std::array<T, N> stdarr;
memcpy(stdarr.data(), arr, N);
return stdarr;
}
TEST(IdClosest, IdenticalKeysAreSameDistance) {
PublicKey pk0;
random_bytes(pk0.data(), CRYPTO_PUBLIC_KEY_SIZE);
PublicKey pk1;
random_bytes(pk1.data(), CRYPTO_PUBLIC_KEY_SIZE);
PublicKey pk2 = pk1;
EXPECT_EQ(id_closest(pk0.data(), pk1.data(), pk2.data()), 0);
}
TEST(IdClosest, DistanceIsCommutative) {
for (uint32_t i = 0; i < 100; ++i) {
PublicKey pk0;
random_bytes(pk0.data(), CRYPTO_PUBLIC_KEY_SIZE);
PublicKey pk1;
random_bytes(pk1.data(), CRYPTO_PUBLIC_KEY_SIZE);
PublicKey pk2;
random_bytes(pk2.data(), CRYPTO_PUBLIC_KEY_SIZE);
ASSERT_NE(pk1, pk2); // RNG can't produce the same random key twice
// Two non-equal keys can't have the same distance from any given key.
EXPECT_NE(id_closest(pk0.data(), pk1.data(), pk2.data()), 0);
if (id_closest(pk0.data(), pk1.data(), pk2.data()) == 1) {
EXPECT_EQ(id_closest(pk0.data(), pk2.data(), pk1.data()), 2);
}
if (id_closest(pk0.data(), pk1.data(), pk2.data()) == 2) {
EXPECT_EQ(id_closest(pk0.data(), pk2.data(), pk1.data()), 1);
}
}
}
TEST(IdClosest, SmallXorDistanceIsCloser) {
PublicKey const pk0 = {{0xaa}};
PublicKey const pk1 = {{0xa0}};
PublicKey const pk2 = {{0x0a}};
EXPECT_EQ(id_closest(pk0.data(), pk1.data(), pk2.data()), 1);
}
TEST(IdClosest, DistinctKeysCannotHaveTheSameDistance) {
PublicKey const pk0 = {{0x06}};
PublicKey const pk1 = {{0x00}};
PublicKey pk2 = {{0x00}};
for (uint8_t i = 1; i < 0xff; ++i) {
pk2[0] = i;
EXPECT_NE(id_closest(pk0.data(), pk1.data(), pk2.data()), 0);
}
}
TEST(AddToList, OverridesKeysWithCloserKeys) {
PublicKey const self_pk = {{0xaa}};
PublicKey const keys[] = {
{{0xa0}}, // closest
{{0x0a}}, //
{{0x0b}}, //
{{0x0c}}, //
{{0x0d}}, //
{{0xa1}}, // closer than the 4 keys above
};
std::array<Node_format, 4> nodes{};
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[0].data(), IP_Port(), self_pk.data()));
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[1].data(), IP_Port(), self_pk.data()));
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[2].data(), IP_Port(), self_pk.data()));
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[3].data(), IP_Port(), self_pk.data()));
EXPECT_EQ(to_array(nodes[0].public_key), keys[0]);
EXPECT_EQ(to_array(nodes[1].public_key), keys[1]);
EXPECT_EQ(to_array(nodes[2].public_key), keys[2]);
EXPECT_EQ(to_array(nodes[3].public_key), keys[3]);
// key 4 is less close than keys 0-3
EXPECT_FALSE(add_to_list(nodes.data(), nodes.size(), keys[4].data(), IP_Port(), self_pk.data()));
// 5 is closer than all except key 0
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[5].data(), IP_Port(), self_pk.data()));
EXPECT_EQ(to_array(nodes[0].public_key), keys[0]);
EXPECT_EQ(to_array(nodes[1].public_key), keys[5]);
EXPECT_EQ(to_array(nodes[2].public_key), keys[1]);
EXPECT_EQ(to_array(nodes[3].public_key), keys[2]);
}
} // namespace