Files
tomato/toxcore/friend_connection_test.cc
Green Sky 9b36dd9d99 Squashed 'external/toxcore/c-toxcore/' changes from c9cdae001..9ed2fa80d
9ed2fa80d fix(toxav): remove extra copy of video frame on encode
de30cf3ad docs: Add new file kinds, that should be useful to all clients.
d5b5e879d fix(DHT): Correct node skipping logic timed out nodes.
30e71fe97 refactor: Generate event dispatch functions and add tox_events_dispatch.
8fdbb0b50 style: Format parameter lists in event handlers.
d00dee12b refactor: Add warning logs when losing chat invites.
b144e8db1 feat: Add a way to look up a file number by ID.
849281ea0 feat: Add a way to fetch groups by chat ID.
a2c177396 refactor: Harden event system and improve type safety.
8f5caa656 refactor: Add MessagePack string support to bin_pack.
34e8d5ad5 chore: Add GitHub CodeQL workflow and local Docker runner.
f7b068010 refactor: Add nullability annotations to event headers.
788abe651 refactor(toxav): Use system allocator for mutexes.
2e4b423eb refactor: Use specific typedefs for public API arrays.
2baf34775 docs(toxav): update idle iteration interval see 679444751876fa3882a717772918ebdc8f083354
2f87ac67b feat: Add Event Loop abstraction (Ev).
f8dfc38d8 test: Fix data race in ToxScenario virtual_clock.
38313921e test(TCP): Add regression test for TCP priority queue integrity.
f94a50d9a refactor(toxav): Replace mutable_mutex with dynamically allocated mutex.
ad054511e refactor: Internalize DHT structs and add debug helpers.
8b467cc96 fix: Prevent potential integer overflow in group chat handshake.
4962bdbb8 test: Improve TCP simulation and add tests
5f0227093 refactor: Allow nullable data in group chat handlers.
e97b18ea9 chore: Improve Windows Docker support.
b14943bbd refactor: Move Logger out of Messenger into Tox.
dd3136250 cleanup: Apply nullability qualifiers to C++ codebase.
1849f70fc refactor: Extract low-level networking code to net and os_network.
8fec75421 refactor: Delete tox_random, align on rng and os_random.
a03ae8051 refactor: Delete tox_memory, align on mem and os_memory.
4c88fed2c refactor: Use `std::` prefixes more consistently in C++ code.
72452f2ae test: Add some more tests for onion and shared key cache.
d5a51b09a cleanup: Use tox_attributes.h in tox_private.h and install it.
b6f5b9fc5 test: Add some benchmarks for various high level things.
8a8d02785 test(support): Introduce threaded Tox runner and simulation barrier
d68d1d095 perf(toxav): optimize audio and video intermediate buffers by keeping them around
REVERT: c9cdae001 fix(toxav): remove extra copy of video frame on encode

git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: 9ed2fa80d582c714d6bdde6a7648220a92cddff8
2026-02-01 14:26:52 +01:00

190 lines
6.7 KiB
C++

#include "friend_connection.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <map>
#include <memory>
#include <vector>
#include "../testing/support/public/simulated_environment.hh"
#include "DHT_test_util.hh"
#include "attributes.h"
#include "crypto_core.h"
#include "logger.h"
#include "mono_time.h"
#include "net_crypto.h"
#include "net_profile.h"
#include "network.h"
#include "onion_client.h"
#include "test_util.hh"
namespace {
using namespace tox::test;
// --- Helper Class ---
template <typename DHTWrapper>
class FriendConnTestNode {
public:
FriendConnTestNode(SimulatedEnvironment &env, std::uint16_t port)
: dht_wrapper_(env, port)
, net_profile_(netprof_new(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory),
[mem = &dht_wrapper_.node().c_memory](Net_Profile *p) { netprof_kill(mem, p); })
, net_crypto_(nullptr, [](Net_Crypto *c) { kill_net_crypto(c); })
, onion_client_(nullptr, [](Onion_Client *c) { kill_onion_client(c); })
, friend_connections_(nullptr, [](Friend_Connections *c) { kill_friend_connections(c); })
{
logger_callback_log(
dht_wrapper_.logger(),
[](void *_Nullable context, Logger_Level level, const char *_Nonnull file,
std::uint32_t line, const char *_Nonnull func, const char *_Nonnull message,
void *_Nullable userdata) {
fprintf(stderr, "[%d] %s:%u: %s: %s\n", level, file, line, func, message);
},
nullptr, nullptr);
// Setup NetCrypto
TCP_Proxy_Info proxy_info = {{0}, TCP_PROXY_NONE};
net_crypto_.reset(new_net_crypto(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
&dht_wrapper_.node().c_random, &dht_wrapper_.node().c_network, dht_wrapper_.mono_time(),
dht_wrapper_.networking(), dht_wrapper_.get_dht(), &DHTWrapper::funcs, &proxy_info,
net_profile_.get()));
new_keys(net_crypto_.get());
// Setup Onion Client
onion_client_.reset(new_onion_client(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
&dht_wrapper_.node().c_random, dht_wrapper_.mono_time(), net_crypto_.get(),
dht_wrapper_.get_dht(), dht_wrapper_.networking()));
// Setup Friend Connections
friend_connections_.reset(
new_friend_connections(dht_wrapper_.logger(), &dht_wrapper_.node().c_memory,
dht_wrapper_.mono_time(), &dht_wrapper_.node().c_network, onion_client_.get(),
dht_wrapper_.get_dht(), net_crypto_.get(), dht_wrapper_.networking(), true));
}
Friend_Connections *_Nonnull get_friend_connections()
{
return REQUIRE_NOT_NULL(friend_connections_.get());
}
Onion_Client *_Nonnull get_onion_client() { return REQUIRE_NOT_NULL(onion_client_.get()); }
Net_Crypto *_Nonnull get_net_crypto() { return REQUIRE_NOT_NULL(net_crypto_.get()); }
DHT *_Nonnull get_dht() { return dht_wrapper_.get_dht(); }
const std::uint8_t *dht_public_key() const { return dht_wrapper_.dht_public_key(); }
const std::uint8_t *real_public_key() const
{
return nc_get_self_public_key(net_crypto_.get());
}
const Random *get_random() { return &dht_wrapper_.node().c_random; }
IP_Port get_ip_port() const { return dht_wrapper_.get_ip_port(); }
void poll()
{
dht_wrapper_.poll();
do_net_crypto(net_crypto_.get(), nullptr);
do_onion_client(onion_client_.get());
do_friend_connections(friend_connections_.get(), nullptr);
}
~FriendConnTestNode();
private:
DHTWrapper dht_wrapper_;
std::unique_ptr<Net_Profile, std::function<void(Net_Profile *)>> net_profile_;
std::unique_ptr<Net_Crypto, void (*)(Net_Crypto *)> net_crypto_;
std::unique_ptr<Onion_Client, void (*)(Onion_Client *)> onion_client_;
std::unique_ptr<Friend_Connections, void (*)(Friend_Connections *)> friend_connections_;
};
template <typename DHTWrapper>
FriendConnTestNode<DHTWrapper>::~FriendConnTestNode() = default;
using FriendConnNode = FriendConnTestNode<WrappedDHT>;
class FriendConnectionTest : public ::testing::Test {
protected:
SimulatedEnvironment env;
};
TEST_F(FriendConnectionTest, CreationAndDestruction)
{
FriendConnNode alice(env, 33445);
EXPECT_NE(alice.get_friend_connections(), nullptr);
}
TEST_F(FriendConnectionTest, AddKillConnection)
{
FriendConnNode alice(env, 33445);
std::uint8_t friend_pk[CRYPTO_PUBLIC_KEY_SIZE];
std::uint8_t friend_sk[CRYPTO_SECRET_KEY_SIZE];
crypto_new_keypair(alice.get_random(), friend_pk, friend_sk);
// Add Connection
int conn_id = new_friend_connection(alice.get_friend_connections(), friend_pk);
EXPECT_NE(conn_id, -1);
// Verify status (should be connecting or none initially, but ID is valid)
EXPECT_NE(
friend_con_connected(alice.get_friend_connections(), conn_id), FRIENDCONN_STATUS_NONE);
// Kill Connection
EXPECT_EQ(kill_friend_connection(alice.get_friend_connections(), conn_id), 0);
}
TEST_F(FriendConnectionTest, ConnectTwoNodes)
{
FriendConnNode alice(env, 33445);
FriendConnNode bob(env, 33446);
// Alice adds Bob as friend
int alice_conn_id
= new_friend_connection(alice.get_friend_connections(), bob.real_public_key());
ASSERT_NE(alice_conn_id, -1);
// Bob adds Alice as friend
int bob_conn_id = new_friend_connection(bob.get_friend_connections(), alice.real_public_key());
ASSERT_NE(bob_conn_id, -1);
// Helper to inject peer info into DHT and trigger connection
auto inject_peer = [](FriendConnNode &self, const FriendConnNode &peer, int conn_id) {
// 1. Tell DHT where the peer is (IP/Port + DHT Public Key)
IP_Port peer_ip = peer.get_ip_port();
addto_lists(self.get_dht(), &peer_ip, peer.dht_public_key());
// 2. Tell friend_connection the peer's DHT Public Key (normally found via Onion)
set_dht_temp_pk(self.get_friend_connections(), conn_id, peer.dht_public_key(), nullptr);
};
inject_peer(alice, bob, alice_conn_id);
inject_peer(bob, alice, bob_conn_id);
auto start = env.clock().current_time_ms();
bool connected = false;
while ((env.clock().current_time_ms() - start) < 5000) { // 5 seconds timeout
alice.poll();
bob.poll();
env.advance_time(10);
if (friend_con_connected(alice.get_friend_connections(), alice_conn_id)
== FRIENDCONN_STATUS_CONNECTED
&& friend_con_connected(bob.get_friend_connections(), bob_conn_id)
== FRIENDCONN_STATUS_CONNECTED) {
connected = true;
break;
}
}
EXPECT_TRUE(connected) << "Alice and Bob failed to connect";
}
} // namespace