Separate run_auto_tests into a library

This commit is contained in:
zugz (tox) 2022-01-25 14:25:36 -05:00 committed by jfreegman
parent 5a88159b8f
commit 1157e4e68c
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
23 changed files with 814 additions and 726 deletions

View File

@ -71,6 +71,7 @@ jobs:
- run: *apt_install
- checkout
- run: infer --no-progress-bar -- cc
auto_tests/auto_test_support.c
auto_tests/lossless_packet_test.c
testing/misc_tools.c
toxav/*.c

View File

@ -106,6 +106,7 @@ jobs:
-o send_message_test
-Wall -Werror
-bench -g
auto_tests/auto_test_support.c
auto_tests/send_message_test.c
testing/misc_tools.c
toxav/*.c
@ -117,6 +118,7 @@ jobs:
- name: Build amalgamation file with TCC
run:
other/make_single_file
auto_tests/auto_test_support.c
auto_tests/send_message_test.c
testing/misc_tools.c |
tcc -
@ -141,6 +143,7 @@ jobs:
-Wno-unknown-pragmas
-Wno-unused-variable
-fstruct-passing -fno-unprototyped -g
auto_tests/auto_test_support.c
auto_tests/send_message_test.c
testing/misc_tools.c
toxav/*.c

View File

@ -391,11 +391,18 @@ endif()
option(AUTOTEST "Enable autotests (mainly for CI)" OFF)
if(AUTOTEST)
add_library(auto_test_support
auto_tests/auto_test_support.c
auto_tests/auto_test_support.h)
target_link_modules(auto_test_support toxcore misc_tools)
endif()
function(auto_test target)
if(AUTOTEST AND NOT (MSVC AND ARGV1 STREQUAL "MSVC_DONT_BUILD"))
add_executable(auto_${target}_test ${CPUFEATURES}
auto_tests/${target}_test.c)
target_link_modules(auto_${target}_test toxcore misc_tools)
target_link_modules(auto_${target}_test toxcore misc_tools auto_test_support)
if(NOT ARGV1 STREQUAL "DONT_RUN")
add_test(NAME ${target} COMMAND ${CROSSCOMPILING_EMULATOR} auto_${target}_test)
set_tests_properties(${target} PROPERTIES TIMEOUT "${TEST_TIMEOUT_SECONDS}")

View File

@ -9,9 +9,17 @@ cc_library(
)
cc_library(
name = "run_auto_test",
name = "auto_test_support",
testonly = True,
hdrs = ["run_auto_test.h"],
srcs = ["auto_test_support.c"],
hdrs = ["auto_test_support.h"],
deps = [
":check_compat",
"//c-toxcore/testing:misc_tools",
"//c-toxcore/toxcore:Messenger",
"//c-toxcore/toxcore:mono_time",
"//c-toxcore/toxcore",
],
)
flaky_tests = {
@ -33,7 +41,7 @@ flaky_tests = {
),
deps = [
":check_compat",
":run_auto_test",
":auto_test_support",
"//c-toxcore/testing:misc_tools",
"//c-toxcore/toxav",
"//c-toxcore/toxcore",

View File

@ -1,5 +1,9 @@
if BUILD_TESTS
noinst_LTLIBRARIES += libauto_test_support.la
libauto_test_support_la_SOURCES = ../auto_tests/auto_test_support.c ../auto_tests/auto_test_support.h
libauto_test_support_la_LIBADD = libmisc_tools.la libtoxcore.la
TESTS = \
conference_double_invite_test \
conference_invite_merge_test \
@ -51,6 +55,7 @@ AUTOTEST_LDADD = \
$(LIBSODIUM_LDFLAGS) \
$(NACL_LDFLAGS) \
libmisc_tools.la \
libauto_test_support.la \
libtoxcore.la \
libtoxencryptsave.la \
$(LIBSODIUM_LIBS) \
@ -239,4 +244,4 @@ endif
EXTRA_DIST += \
$(top_srcdir)/auto_tests/data/save.tox \
$(top_srcdir)/auto_tests/check_compat.h \
$(top_srcdir)/auto_tests/run_auto_test.h
$(top_srcdir)/auto_tests/auto_test_support.h

View File

@ -0,0 +1,309 @@
#include <stdlib.h> // calloc, free
#include "check_compat.h"
#include "../testing/misc_tools.h"
#include "../toxcore/Messenger.h"
#include "../toxcore/mono_time.h"
#include "auto_test_support.h"
const Run_Auto_Options default_run_auto_options = { GRAPH_COMPLETE, nullptr };
// List of live bootstrap nodes. These nodes should have TCP server enabled.
static const struct BootstrapNodes {
const char *ip;
uint16_t port;
const uint8_t key[32];
} BootstrapNodes[] = {
#ifndef USE_TEST_NETWORK
{
"tox.abilinski.com", 33445,
0x10, 0xC0, 0x0E, 0xB2, 0x50, 0xC3, 0x23, 0x3E,
0x34, 0x3E, 0x2A, 0xEB, 0xA0, 0x71, 0x15, 0xA5,
0xC2, 0x89, 0x20, 0xE9, 0xC8, 0xD2, 0x94, 0x92,
0xF6, 0xD0, 0x0B, 0x29, 0x04, 0x9E, 0xDC, 0x7E,
},
{
"tox.initramfs.io", 33445,
0x02, 0x80, 0x7C, 0xF4, 0xF8, 0xBB, 0x8F, 0xB3,
0x90, 0xCC, 0x37, 0x94, 0xBD, 0xF1, 0xE8, 0x44,
0x9E, 0x9A, 0x83, 0x92, 0xC5, 0xD3, 0xF2, 0x20,
0x00, 0x19, 0xDA, 0x9F, 0x1E, 0x81, 0x2E, 0x46,
},
{
"tox.plastiras.org", 33445,
0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F,
0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33,
0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED,
0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25,
},
{
"tox.novg.net", 33445,
0xD5, 0x27, 0xE5, 0x84, 0x7F, 0x83, 0x30, 0xD6,
0x28, 0xDA, 0xB1, 0x81, 0x4F, 0x0A, 0x42, 0x2F,
0x6D, 0xC9, 0xD0, 0xA3, 0x00, 0xE6, 0xC3, 0x57,
0x63, 0x4E, 0xE2, 0xDA, 0x88, 0xC3, 0x54, 0x63,
},
#else
{
"172.93.52.70", 33445,
0x79, 0xCA, 0xDA, 0x49, 0x74, 0xB0, 0x92, 0x6F,
0x28, 0x6F, 0x02, 0x5C, 0xD5, 0xFF, 0xDF, 0x3E,
0x65, 0x4A, 0x37, 0x58, 0xC5, 0x3E, 0x02, 0x73,
0xEC, 0xFC, 0x4D, 0x12, 0xC2, 0x1D, 0xCA, 0x48,
},
#endif // USE_TEST_NETWORK
{ nullptr, 0, 0 },
};
void bootstrap_tox_live_network(Tox *tox, bool enable_tcp)
{
for (size_t j = 0; BootstrapNodes[j].ip != nullptr; ++j) {
const char *ip = BootstrapNodes[j].ip;
uint16_t port = BootstrapNodes[j].port;
const uint8_t *key = BootstrapNodes[j].key;
Tox_Err_Bootstrap err;
tox_bootstrap(tox, ip, port, key, &err);
if (err != TOX_ERR_BOOTSTRAP_OK) {
fprintf(stderr, "Failed to bootstrap node %zu (%s): error %d\n", j, ip, err);
}
if (enable_tcp) {
tox_add_tcp_relay(tox, ip, port, key, &err);
if (err != TOX_ERR_BOOTSTRAP_OK) {
fprintf(stderr, "Failed to add TCP relay %zu (%s): error %d\n", j, ip, err);
}
}
}
}
bool all_connected(uint32_t tox_count, AutoTox *autotoxes)
{
for (uint32_t i = 0; i < tox_count; ++i) {
if (tox_self_get_connection_status(autotoxes[i].tox) == TOX_CONNECTION_NONE) {
return false;
}
}
return true;
}
bool all_friends_connected(uint32_t tox_count, AutoTox *autotoxes)
{
for (uint32_t i = 0; i < tox_count; ++i) {
const size_t friend_count = tox_self_get_friend_list_size(autotoxes[i].tox);
for (size_t j = 0; j < friend_count; ++j) {
if (tox_friend_get_connection_status(autotoxes[i].tox, j, nullptr) == TOX_CONNECTION_NONE) {
return false;
}
}
}
return true;
}
void iterate_all_wait(uint32_t tox_count, AutoTox *autotoxes, uint32_t wait)
{
for (uint32_t i = 0; i < tox_count; ++i) {
if (autotoxes[i].alive) {
tox_iterate(autotoxes[i].tox, &autotoxes[i]);
autotoxes[i].clock += wait;
}
}
/* Also actually sleep a little, to allow for local network processing */
c_sleep(5);
}
static uint64_t get_state_clock_callback(Mono_Time *mono_time, void *user_data)
{
const uint64_t *clock = (const uint64_t *)user_data;
return *clock;
}
void set_mono_time_callback(AutoTox *autotox)
{
// TODO(iphydf): Don't rely on toxcore internals.
Mono_Time *mono_time = ((Messenger *)autotox->tox)->mono_time;
autotox->clock = current_time_monotonic(mono_time);
mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &autotox->clock);
}
void save_autotox(AutoTox *autotox)
{
ck_assert(autotox != nullptr);
fprintf(stderr, "Saving #%u\n", autotox->index);
free(autotox->save_state);
autotox->save_state = nullptr;
autotox->save_size = tox_get_savedata_size(autotox->tox);
ck_assert_msg(autotox->save_size > 0, "save is invalid size %u", (unsigned)autotox->save_size);
autotox->save_state = (uint8_t *)malloc(autotox->save_size);
ck_assert_msg(autotox->save_state != nullptr, "malloc failed");
tox_get_savedata(autotox->tox, autotox->save_state);
}
void kill_autotox(AutoTox *autotox)
{
ck_assert(autotox != nullptr);
ck_assert(autotox->alive);
fprintf(stderr, "Killing #%u\n", autotox->index);
autotox->alive = false;
tox_kill(autotox->tox);
}
void reload(AutoTox *autotox)
{
ck_assert(autotox != nullptr);
if (autotox->alive) {
kill_autotox(autotox);
}
fprintf(stderr, "Reloading #%u\n", autotox->index);
ck_assert(autotox->save_state != nullptr);
struct Tox_Options *const options = tox_options_new(nullptr);
ck_assert(options != nullptr);
tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_options_set_savedata_data(options, autotox->save_state, autotox->save_size);
autotox->tox = tox_new_log(options, nullptr, &autotox->index);
ck_assert(autotox->tox != nullptr);
tox_options_free(options);
set_mono_time_callback(autotox);
autotox->alive = true;
}
static void initialise_autotox(struct Tox_Options *options, AutoTox *autotox, uint32_t index, uint32_t state_size,
const Run_Auto_Options *autotest_opts)
{
autotox->index = index;
autotox->tox = tox_new_log(options, nullptr, &autotox->index);
ck_assert_msg(autotox->tox != nullptr, "failed to create tox instance #%u", index);
set_mono_time_callback(autotox);
autotox->alive = true;
autotox->save_state = nullptr;
if (state_size > 0) {
autotox->state = calloc(1, state_size);
ck_assert(autotox->state != nullptr);
ck_assert_msg(autotox->state != nullptr, "failed to allocate state");
} else {
autotox->state = nullptr;
}
if (autotest_opts->init_autotox != nullptr) {
autotest_opts->init_autotox(autotox, index);
}
}
static void autotox_add_friend(AutoTox *autotoxes, uint32_t adding, uint32_t added)
{
uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
tox_self_get_public_key(autotoxes[added].tox, public_key);
Tox_Err_Friend_Add err;
tox_friend_add_norequest(autotoxes[adding].tox, public_key, &err);
ck_assert(err == TOX_ERR_FRIEND_ADD_OK);
}
static void initialise_friend_graph(Graph_Type graph, uint32_t num_toxes, AutoTox *autotoxes)
{
if (graph == GRAPH_LINEAR) {
printf("toxes #%u-#%u each add adjacent toxes as friends\n", 0, num_toxes - 1);
for (uint32_t i = 0; i < num_toxes; ++i) {
for (uint32_t j = i - 1; j != i + 3; j += 2) {
if (j < num_toxes) {
autotox_add_friend(autotoxes, i, j);
}
}
}
} else if (graph == GRAPH_COMPLETE) {
printf("toxes #%u-#%u add each other as friends\n", 0, num_toxes - 1);
for (uint32_t i = 0; i < num_toxes; ++i) {
for (uint32_t j = 0; j < num_toxes; ++j) {
if (i != j) {
autotox_add_friend(autotoxes, i, j);
}
}
}
} else {
ck_abort_msg("Unknown graph type");
}
}
static void bootstrap_autotoxes(struct Tox_Options *options, uint32_t tox_count, const Run_Auto_Options *autotest_opts,
AutoTox *autotoxes)
{
const bool udp_enabled = options != nullptr ? tox_options_get_udp_enabled(options) : true;
if (udp_enabled) {
printf("bootstrapping all toxes off tox 0\n");
uint8_t dht_key[TOX_PUBLIC_KEY_SIZE];
tox_self_get_dht_id(autotoxes[0].tox, dht_key);
const uint16_t dht_port = tox_self_get_udp_port(autotoxes[0].tox, nullptr);
for (uint32_t i = 1; i < tox_count; ++i) {
Tox_Err_Bootstrap err;
tox_bootstrap(autotoxes[i].tox, "localhost", dht_port, dht_key, &err);
ck_assert(err == TOX_ERR_BOOTSTRAP_OK);
}
} else {
printf("bootstrapping all toxes to tcp relays\n");
for (uint32_t i = 0; i < tox_count; ++i) {
bootstrap_tox_live_network(autotoxes[i].tox, true);
}
}
}
void run_auto_test(struct Tox_Options *options, uint32_t tox_count, void test(AutoTox *autotoxes),
uint32_t state_size, const Run_Auto_Options *autotest_opts)
{
printf("initialising %u toxes\n", tox_count);
AutoTox *autotoxes = (AutoTox *)calloc(tox_count, sizeof(AutoTox));
ck_assert(autotoxes != nullptr);
for (uint32_t i = 0; i < tox_count; ++i) {
initialise_autotox(options, &autotoxes[i], i, state_size, autotest_opts);
}
initialise_friend_graph(autotest_opts->graph, tox_count, autotoxes);
bootstrap_autotoxes(options, tox_count, autotest_opts, autotoxes);
do {
iterate_all_wait(tox_count, autotoxes, ITERATION_INTERVAL);
} while (!all_connected(tox_count, autotoxes));
printf("toxes are online\n");
do {
iterate_all_wait(tox_count, autotoxes, ITERATION_INTERVAL);
} while (!all_friends_connected(tox_count, autotoxes));
printf("tox clients connected\n");
test(autotoxes);
for (uint32_t i = 0; i < tox_count; ++i) {
tox_kill(autotoxes[i].tox);
free(autotoxes[i].state);
free(autotoxes[i].save_state);
}
free(autotoxes);
}

View File

@ -0,0 +1,53 @@
#ifndef RUN_AUTO_TEST_H
#define RUN_AUTO_TEST_H
#include <stdlib.h> // calloc, free
#include "check_compat.h"
#include "../testing/misc_tools.h"
#include "../toxcore/Messenger.h"
#include "../toxcore/mono_time.h"
typedef struct AutoTox {
Tox *tox;
uint32_t index;
uint64_t clock;
size_t save_size;
uint8_t *save_state;
bool alive;
void *state;
} AutoTox;
bool all_connected(uint32_t tox_count, AutoTox *toxes);
bool all_friends_connected(uint32_t tox_count, AutoTox *toxes);
void iterate_all_wait(uint32_t tox_count, AutoTox *toxes, uint32_t wait);
void save_autotox(AutoTox *autotox);
void kill_autotox(AutoTox *autotox);
void reload(AutoTox *autotox);
void set_mono_time_callback(AutoTox *tox);
typedef enum Graph_Type {
GRAPH_COMPLETE = 0,
GRAPH_LINEAR
} Graph_Type;
typedef struct Run_Auto_Options {
Graph_Type graph;
void (*init_autotox)(AutoTox *autotox, uint32_t n);
} Run_Auto_Options;
extern const Run_Auto_Options default_run_auto_options;
void run_auto_test(struct Tox_Options *options, uint32_t tox_count, void test(AutoTox *autotoxes),
uint32_t state_size, const Run_Auto_Options *autotest_opts);
void bootstrap_tox_live_network(Tox *tox, bool enable_tcp);
#endif

View File

@ -3,12 +3,7 @@
#include "../testing/misc_tools.h"
#include "check_compat.h"
typedef struct State {
uint32_t index;
uint64_t clock;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
int main(void)
{
@ -16,7 +11,7 @@ int main(void)
Tox *tox_udp = tox_new_log(nullptr, nullptr, nullptr);
bootstrap_toxes_live_network(&tox_udp, 1, false);
bootstrap_tox_live_network(tox_udp, false);
printf("Waiting for connection");
@ -35,7 +30,5 @@ int main(void)
tox_kill(tox_udp);
(void)run_auto_test;
return 0;
}

View File

@ -13,51 +13,49 @@
#define NUM_AV_DISCONNECT (NUM_AV_GROUP_TOX / 2)
#define NUM_AV_DISABLE (NUM_AV_GROUP_TOX / 2)
typedef struct State {
uint32_t index;
uint64_t clock;
#include "auto_test_support.h"
typedef struct State {
bool invited_next;
uint32_t received_audio_peers[NUM_AV_GROUP_TOX];
uint32_t received_audio_num;
} State;
#include "run_auto_test.h"
static void handle_self_connection_status(
Tox *tox, Tox_Connection connection_status, void *user_data)
{
const State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
if (connection_status != TOX_CONNECTION_NONE) {
printf("tox #%u: is now connected\n", state->index);
printf("tox #%u: is now connected\n", autotox->index);
} else {
printf("tox #%u: is now disconnected\n", state->index);
printf("tox #%u: is now disconnected\n", autotox->index);
}
}
static void handle_friend_connection_status(
Tox *tox, uint32_t friendnumber, Tox_Connection connection_status, void *user_data)
{
const State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
if (connection_status != TOX_CONNECTION_NONE) {
printf("tox #%u: is now connected to friend %u\n", state->index, friendnumber);
printf("tox #%u: is now connected to friend %u\n", autotox->index, friendnumber);
} else {
printf("tox #%u: is now disconnected from friend %u\n", state->index, friendnumber);
printf("tox #%u: is now disconnected from friend %u\n", autotox->index, friendnumber);
}
}
static void audio_callback(void *tox, uint32_t groupnumber, uint32_t peernumber,
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
sample_rate, void *userdata)
sample_rate, void *user_data)
{
if (samples == 0) {
return;
}
State *state = (State *)userdata;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
for (uint32_t i = 0; i < state->received_audio_num; ++i) {
if (state->received_audio_peers[i] == peernumber) {
@ -75,17 +73,18 @@ static void handle_conference_invite(
Tox *tox, uint32_t friendnumber, Tox_Conference_Type type,
const uint8_t *data, size_t length, void *user_data)
{
const State *state = (State *)user_data;
ck_assert_msg(type == TOX_CONFERENCE_TYPE_AV, "tox #%u: wrong conference type: %d", state->index, type);
const AutoTox *autotox = (AutoTox *)user_data;
ck_assert_msg(type == TOX_CONFERENCE_TYPE_AV, "tox #%u: wrong conference type: %d", autotox->index, type);
ck_assert_msg(toxav_join_av_groupchat(tox, friendnumber, data, length, audio_callback, user_data) == 0,
"tox #%u: failed to join group", state->index);
"tox #%u: failed to join group", autotox->index);
}
static void handle_conference_connected(
Tox *tox, uint32_t conference_number, void *user_data)
{
State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
if (state->invited_next || tox_self_get_friend_list_size(tox) <= 1) {
return;
@ -93,12 +92,13 @@ static void handle_conference_connected(
Tox_Err_Conference_Invite err;
tox_conference_invite(tox, 1, 0, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox #%u failed to invite next friend: err = %d", state->index, err);
printf("tox #%u: invited next friend\n", state->index);
ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox #%u failed to invite next friend: err = %d", autotox->index,
err);
printf("tox #%u: invited next friend\n", autotox->index);
state->invited_next = true;
}
static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
static bool toxes_are_disconnected_from_group(uint32_t tox_count, AutoTox *autotoxes,
bool *disconnected)
{
uint32_t num_disconnected = 0;
@ -112,7 +112,7 @@ static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
continue;
}
if (tox_conference_peer_count(toxes[i], 0, nullptr) > tox_count - num_disconnected) {
if (tox_conference_peer_count(autotoxes[i].tox, 0, nullptr) > tox_count - num_disconnected) {
return false;
}
}
@ -120,7 +120,7 @@ static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
return true;
}
static void disconnect_toxes(uint32_t tox_count, Tox **toxes, State *state,
static void disconnect_toxes(uint32_t tox_count, AutoTox *autotoxes,
const bool *disconnect, const bool *exclude)
{
/* Fake a network outage for a set of peers D by iterating only the other
@ -138,22 +138,22 @@ static void disconnect_toxes(uint32_t tox_count, Tox **toxes, State *state,
do {
for (uint32_t i = 0; i < tox_count; ++i) {
if (!disconnect_now[i]) {
tox_iterate(toxes[i], &state[i]);
state[i].clock += 1000;
tox_iterate(autotoxes[i].tox, &autotoxes[i]);
autotoxes[i].clock += 1000;
}
}
c_sleep(20);
} while (!toxes_are_disconnected_from_group(tox_count, toxes, disconnect_now));
} while (!toxes_are_disconnected_from_group(tox_count, autotoxes, disconnect_now));
invert = !invert;
} while (invert);
}
static bool all_connected_to_group(uint32_t tox_count, Tox **toxes)
static bool all_connected_to_group(uint32_t tox_count, AutoTox *autotoxes)
{
for (uint32_t i = 0; i < tox_count; ++i) {
if (tox_conference_peer_count(toxes[i], 0, nullptr) < tox_count) {
if (tox_conference_peer_count(autotoxes[i].tox, 0, nullptr) < tox_count) {
return false;
}
}
@ -176,7 +176,7 @@ static uint32_t random_false_index(bool *list, const uint32_t length)
return index;
}
static bool all_got_audio(State *state, const bool *disabled)
static bool all_got_audio(AutoTox *autotoxes, const bool *disabled)
{
uint32_t num_disabled = 0;
@ -185,7 +185,9 @@ static bool all_got_audio(State *state, const bool *disabled)
}
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
if (disabled[i] ^ (state[i].received_audio_num
State *state = (State *)autotoxes[i].state;
if (disabled[i] ^ (state->received_audio_num
!= NUM_AV_GROUP_TOX - num_disabled - 1)) {
return false;
}
@ -194,10 +196,10 @@ static bool all_got_audio(State *state, const bool *disabled)
return true;
}
static void reset_received_audio(Tox **toxes, State *state)
static void reset_received_audio(AutoTox *autotoxes)
{
for (uint32_t j = 0; j < NUM_AV_GROUP_TOX; ++j) {
state[j].received_audio_num = 0;
((State *)autotoxes[j].state)->received_audio_num = 0;
}
}
@ -209,7 +211,7 @@ static void reset_received_audio(Tox **toxes, State *state)
* buffers fill up. */
#define GROUP_AV_AUDIO_ITERATIONS (8 + NUM_AV_GROUP_TOX)
static bool test_audio(Tox **toxes, State *state, const bool *disabled, bool quiet)
static bool test_audio(AutoTox *autotoxes, const bool *disabled, bool quiet)
{
if (!quiet) {
printf("testing sending and receiving audio\n");
@ -217,7 +219,7 @@ static bool test_audio(Tox **toxes, State *state, const bool *disabled, bool qui
const int16_t PCM[GROUP_AV_TEST_SAMPLES] = {0};
reset_received_audio(toxes, state);
reset_received_audio(autotoxes);
for (uint32_t n = 0; n < GROUP_AV_AUDIO_ITERATIONS; ++n) {
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
@ -225,18 +227,18 @@ static bool test_audio(Tox **toxes, State *state, const bool *disabled, bool qui
continue;
}
if (toxav_group_send_audio(toxes[i], 0, PCM, GROUP_AV_TEST_SAMPLES, 1, 48000) != 0) {
if (toxav_group_send_audio(autotoxes[i].tox, 0, PCM, GROUP_AV_TEST_SAMPLES, 1, 48000) != 0) {
if (!quiet) {
ck_abort_msg("#%u failed to send audio", state[i].index);
ck_abort_msg("#%u failed to send audio", autotoxes[i].index);
}
return false;
}
}
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(NUM_AV_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
if (all_got_audio(state, disabled)) {
if (all_got_audio(autotoxes, disabled)) {
return true;
}
}
@ -248,32 +250,32 @@ static bool test_audio(Tox **toxes, State *state, const bool *disabled, bool qui
return false;
}
static void test_eventual_audio(Tox **toxes, State *state, const bool *disabled, uint64_t timeout)
static void test_eventual_audio(AutoTox *autotoxes, const bool *disabled, uint64_t timeout)
{
uint64_t start = state[0].clock;
uint64_t start = autotoxes[0].clock;
while (state[0].clock < start + timeout) {
if (test_audio(toxes, state, disabled, true)
&& test_audio(toxes, state, disabled, true)) {
printf("audio test successful after %d seconds\n", (int)((state[0].clock - start) / 1000));
while (autotoxes[0].clock < start + timeout) {
if (test_audio(autotoxes, disabled, true)
&& test_audio(autotoxes, disabled, true)) {
printf("audio test successful after %d seconds\n", (int)((autotoxes[0].clock - start) / 1000));
return;
}
}
printf("audio seems not to be getting through: testing again with errors.\n");
test_audio(toxes, state, disabled, false);
test_audio(autotoxes, disabled, false);
}
static void do_audio(Tox **toxes, State *state, uint32_t iterations)
static void do_audio(AutoTox *autotoxes, uint32_t iterations)
{
const int16_t PCM[GROUP_AV_TEST_SAMPLES] = {0};
printf("running audio for %u iterations\n", iterations);
for (uint32_t f = 0; f < iterations; ++f) {
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
ck_assert_msg(toxav_group_send_audio(toxes[i], 0, PCM, GROUP_AV_TEST_SAMPLES, 1, 48000) == 0,
"#%u failed to send audio", state[i].index);
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
ck_assert_msg(toxav_group_send_audio(autotoxes[i].tox, 0, PCM, GROUP_AV_TEST_SAMPLES, 1, 48000) == 0,
"#%u failed to send audio", autotoxes[i].index);
iterate_all_wait(NUM_AV_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
}
}
}
@ -283,15 +285,15 @@ static void do_audio(Tox **toxes, State *state, uint32_t iterations)
#define JITTER_SETTLE_TIME (GROUP_JBUF_DEAD_SECONDS*1000 + NUM_AV_GROUP_TOX*ITERATION_INTERVAL*(GROUP_AV_AUDIO_ITERATIONS+1))
static void run_conference_tests(Tox **toxes, State *state)
static void run_conference_tests(AutoTox *autotoxes)
{
bool disabled[NUM_AV_GROUP_TOX] = {0};
test_audio(toxes, state, disabled, false);
test_audio(autotoxes, disabled, false);
/* have everyone send audio for a bit so we can test that the audio
* sequnums dropping to 0 on restart isn't a problem */
do_audio(toxes, state, 20);
do_audio(autotoxes, 20);
printf("letting random toxes timeout\n");
bool disconnected[NUM_AV_GROUP_TOX] = {0};
@ -305,55 +307,41 @@ static void run_conference_tests(Tox **toxes, State *state)
if (i < NUM_AV_DISCONNECT / 2) {
restarting[disconnect] = true;
printf("Restarting #%u\n", state[disconnect].index);
printf("Restarting #%u\n", autotoxes[disconnect].index);
} else {
printf("Disconnecting #%u\n", state[disconnect].index);
printf("Disconnecting #%u\n", autotoxes[disconnect].index);
}
}
uint8_t *save[NUM_AV_GROUP_TOX];
size_t save_size[NUM_AV_GROUP_TOX];
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
if (restarting[i]) {
save_size[i] = tox_get_savedata_size(toxes[i]);
ck_assert_msg(save_size[i] != 0, "save is invalid size %u", (unsigned)save_size[i]);
save[i] = (uint8_t *)malloc(save_size[i]);
ck_assert_msg(save[i] != nullptr, "malloc failed");
tox_get_savedata(toxes[i], save[i]);
tox_kill(toxes[i]);
save_autotox(&autotoxes[i]);
kill_autotox(&autotoxes[i]);
}
}
disconnect_toxes(NUM_AV_GROUP_TOX, toxes, state, disconnected, restarting);
disconnect_toxes(NUM_AV_GROUP_TOX, autotoxes, disconnected, restarting);
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
if (restarting[i]) {
struct Tox_Options *const options = tox_options_new(nullptr);
tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_options_set_savedata_data(options, save[i], save_size[i]);
toxes[i] = tox_new_log(options, nullptr, &state[i].index);
tox_options_free(options);
free(save[i]);
set_mono_time_callback(toxes[i], &state[i]);
reload(&autotoxes[i]);
}
}
printf("reconnecting toxes\n");
do {
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
} while (!all_connected_to_group(NUM_AV_GROUP_TOX, toxes));
iterate_all_wait(NUM_AV_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
} while (!all_connected_to_group(NUM_AV_GROUP_TOX, autotoxes));
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
if (restarting[i]) {
ck_assert_msg(!toxav_groupchat_av_enabled(toxes[i], 0),
"#%u restarted but av enabled", state[i].index);
ck_assert_msg(toxav_groupchat_enable_av(toxes[i], 0, audio_callback, &state[i]) == 0,
"#%u failed to re-enable av", state[i].index);
ck_assert_msg(toxav_groupchat_av_enabled(toxes[i], 0),
"#%u av not enabled even after enabling", state[i].index);
ck_assert_msg(!toxav_groupchat_av_enabled(autotoxes[i].tox, 0),
"#%u restarted but av enabled", autotoxes[i].index);
ck_assert_msg(toxav_groupchat_enable_av(autotoxes[i].tox, 0, audio_callback, &autotoxes[i]) == 0,
"#%u failed to re-enable av", autotoxes[i].index);
ck_assert_msg(toxav_groupchat_av_enabled(autotoxes[i].tox, 0),
"#%u av not enabled even after enabling", autotoxes[i].index);
}
}
@ -363,7 +351,7 @@ static void run_conference_tests(Tox **toxes, State *state)
* connected enough for lossy messages to get through
* (all_connected_to_group() only checks lossless connectivity, which is a
* looser condition). */
test_eventual_audio(toxes, state, disabled, JITTER_SETTLE_TIME + NUM_AV_GROUP_TOX * 1000);
test_eventual_audio(autotoxes, disabled, JITTER_SETTLE_TIME + NUM_AV_GROUP_TOX * 1000);
printf("testing disabling av\n");
@ -372,18 +360,18 @@ static void run_conference_tests(Tox **toxes, State *state)
for (uint32_t i = 0; i < NUM_AV_DISABLE; ++i) {
uint32_t disable = random_false_index(disabled, NUM_AV_GROUP_TOX);
disabled[disable] = true;
printf("Disabling #%u\n", state[disable].index);
ck_assert_msg(toxav_groupchat_enable_av(toxes[disable], 0, audio_callback, &state[disable]) != 0,
"#%u could enable already enabled av!", state[i].index);
ck_assert_msg(toxav_groupchat_disable_av(toxes[disable], 0) == 0,
"#%u failed to disable av", state[i].index);
printf("Disabling #%u\n", autotoxes[disable].index);
ck_assert_msg(toxav_groupchat_enable_av(autotoxes[disable].tox, 0, audio_callback, &autotoxes[disable]) != 0,
"#%u could enable already enabled av!", autotoxes[i].index);
ck_assert_msg(toxav_groupchat_disable_av(autotoxes[disable].tox, 0) == 0,
"#%u failed to disable av", autotoxes[i].index);
}
// Run test without error to clear out messages from now-disabled peers.
test_audio(toxes, state, disabled, true);
test_audio(autotoxes, disabled, true);
printf("testing audio with some peers having disabled their av\n");
test_audio(toxes, state, disabled, false);
test_audio(autotoxes, disabled, false);
for (uint32_t i = 0; i < NUM_AV_DISABLE; ++i) {
if (!disabled[i]) {
@ -391,59 +379,60 @@ static void run_conference_tests(Tox **toxes, State *state)
}
disabled[i] = false;
ck_assert_msg(toxav_groupchat_disable_av(toxes[i], 0) != 0,
"#%u could disable already disabled av!", state[i].index);
ck_assert_msg(!toxav_groupchat_av_enabled(toxes[i], 0),
"#%u av enabled after disabling", state[i].index);
ck_assert_msg(toxav_groupchat_enable_av(toxes[i], 0, audio_callback, &state[i]) == 0,
"#%u failed to re-enable av", state[i].index);
ck_assert_msg(toxav_groupchat_disable_av(autotoxes[i].tox, 0) != 0,
"#%u could disable already disabled av!", autotoxes[i].index);
ck_assert_msg(!toxav_groupchat_av_enabled(autotoxes[i].tox, 0),
"#%u av enabled after disabling", autotoxes[i].index);
ck_assert_msg(toxav_groupchat_enable_av(autotoxes[i].tox, 0, audio_callback, &autotoxes[i]) == 0,
"#%u failed to re-enable av", autotoxes[i].index);
}
printf("testing audio after re-enabling all av\n");
test_eventual_audio(toxes, state, disabled, JITTER_SETTLE_TIME);
test_eventual_audio(autotoxes, disabled, JITTER_SETTLE_TIME);
}
static void test_groupav(Tox **toxes, State *state)
static void test_groupav(AutoTox *autotoxes)
{
const time_t test_start_time = time(nullptr);
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
tox_callback_self_connection_status(toxes[i], &handle_self_connection_status);
tox_callback_friend_connection_status(toxes[i], &handle_friend_connection_status);
tox_callback_conference_invite(toxes[i], &handle_conference_invite);
tox_callback_conference_connected(toxes[i], &handle_conference_connected);
tox_callback_self_connection_status(autotoxes[i].tox, &handle_self_connection_status);
tox_callback_friend_connection_status(autotoxes[i].tox, &handle_friend_connection_status);
tox_callback_conference_invite(autotoxes[i].tox, &handle_conference_invite);
tox_callback_conference_connected(autotoxes[i].tox, &handle_conference_connected);
}
ck_assert_msg(toxav_add_av_groupchat(toxes[0], audio_callback, &state[0]) != UINT32_MAX, "failed to create group");
printf("tox #%u: inviting its first friend\n", state[0].index);
ck_assert_msg(tox_conference_invite(toxes[0], 0, 0, nullptr) != 0, "failed to invite friend");
state[0].invited_next = true;
ck_assert_msg(toxav_add_av_groupchat(autotoxes[0].tox, audio_callback, &autotoxes[0]) != UINT32_MAX,
"failed to create group");
printf("tox #%u: inviting its first friend\n", autotoxes[0].index);
ck_assert_msg(tox_conference_invite(autotoxes[0].tox, 0, 0, nullptr) != 0, "failed to invite friend");
((State *)autotoxes[0].state)->invited_next = true;
printf("waiting for invitations to be made\n");
uint32_t invited_count = 0;
do {
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(NUM_AV_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
invited_count = 0;
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
invited_count += state[i].invited_next;
invited_count += ((State *)autotoxes[i].state)->invited_next;
}
} while (invited_count != NUM_AV_GROUP_TOX - 1);
uint64_t pregroup_clock = state[0].clock;
uint64_t pregroup_clock = autotoxes[0].clock;
printf("waiting for all toxes to be in the group\n");
uint32_t fully_connected_count = 0;
do {
fully_connected_count = 0;
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(NUM_AV_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
Tox_Err_Conference_Peer_Query err;
uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, &err);
uint32_t peer_count = tox_conference_peer_count(autotoxes[i].tox, 0, &err);
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
peer_count = 0;
@ -453,9 +442,9 @@ static void test_groupav(Tox **toxes, State *state)
}
} while (fully_connected_count != NUM_AV_GROUP_TOX);
printf("group connected, took %d seconds\n", (int)((state[0].clock - pregroup_clock) / 1000));
printf("group connected, took %d seconds\n", (int)((autotoxes[0].clock - pregroup_clock) / 1000));
run_conference_tests(toxes, state);
run_conference_tests(autotoxes);
printf("test_many_group succeeded, took %d seconds\n", (int)(time(nullptr) - test_start_time));
}
@ -464,6 +453,10 @@ int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, NUM_AV_GROUP_TOX, test_groupav, true);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, NUM_AV_GROUP_TOX, test_groupav, sizeof(State), &options);
return 0;
}

View File

@ -2,9 +2,6 @@
#include <stdint.h>
typedef struct State {
uint32_t index;
uint64_t clock;
bool self_online;
bool friend_online;
@ -12,17 +9,18 @@ typedef struct State {
uint32_t conference;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
static void handle_conference_invite(
Tox *tox, uint32_t friend_number, Tox_Conference_Type type,
const uint8_t *cookie, size_t length, void *user_data)
{
State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
fprintf(stderr, "handle_conference_invite(#%u, %u, %d, uint8_t[%u], _)\n",
state->index, friend_number, type, (unsigned)length);
fprintf(stderr, "tox%u joining conference\n", state->index);
autotox->index, friend_number, type, (unsigned)length);
fprintf(stderr, "tox%u joining conference\n", autotox->index);
ck_assert_msg(!state->joined, "invitation callback generated for already joined conference");
@ -31,31 +29,35 @@ static void handle_conference_invite(
state->conference = tox_conference_join(tox, friend_number, cookie, length, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK,
"attempting to join the conference returned with an error: %d", err);
fprintf(stderr, "tox%u joined conference %u\n", state->index, state->conference);
fprintf(stderr, "tox%u joined conference %u\n", autotox->index, state->conference);
state->joined = true;
}
}
static void conference_double_invite_test(Tox **toxes, State *state)
static void conference_double_invite_test(AutoTox *autotoxes)
{
// Conference callbacks.
tox_callback_conference_invite(toxes[0], handle_conference_invite);
tox_callback_conference_invite(toxes[1], handle_conference_invite);
tox_callback_conference_invite(autotoxes[0].tox, handle_conference_invite);
tox_callback_conference_invite(autotoxes[1].tox, handle_conference_invite);
State *state[2];
state[0] = (State *)autotoxes[0].state;
state[1] = (State *)autotoxes[1].state;
{
// Create new conference, tox0 is the founder.
Tox_Err_Conference_New err;
state[0].conference = tox_conference_new(toxes[0], &err);
state[0].joined = true;
state[0]->conference = tox_conference_new(autotoxes[0].tox, &err);
state[0]->joined = true;
ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK,
"attempting to create a new conference returned with an error: %d", err);
fprintf(stderr, "Created conference: index=%u\n", state[0].conference);
fprintf(stderr, "Created conference: index=%u\n", state[0]->conference);
}
{
// Invite friend.
Tox_Err_Conference_Invite err;
tox_conference_invite(toxes[0], 0, state[0].conference, &err);
tox_conference_invite(autotoxes[0].tox, 0, state[0]->conference, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK,
"attempting to invite a friend returned with an error: %d", err);
fprintf(stderr, "tox0 invited tox1\n");
@ -64,21 +66,25 @@ static void conference_double_invite_test(Tox **toxes, State *state)
fprintf(stderr, "Waiting for invitation to arrive\n");
do {
iterate_all_wait(2, toxes, state, ITERATION_INTERVAL);
} while (!state[0].joined || !state[1].joined);
iterate_all_wait(2, autotoxes, ITERATION_INTERVAL);
} while (!state[0]->joined || !state[1]->joined);
fprintf(stderr, "Invitations accepted\n");
fprintf(stderr, "Sending second invitation; should be ignored\n");
tox_conference_invite(toxes[0], 0, state[0].conference, nullptr);
tox_conference_invite(autotoxes[0].tox, 0, state[0]->conference, nullptr);
iterate_all_wait(2, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(2, autotoxes, ITERATION_INTERVAL);
}
int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, 2, conference_double_invite_test, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, 2, conference_double_invite_test, sizeof(State), &options);
return 0;
}

View File

@ -3,133 +3,72 @@
#include <stdlib.h>
typedef struct State {
uint32_t index;
uint64_t clock;
size_t save_size;
uint8_t *save_state;
bool alive;
bool connected;
uint32_t conference;
} State;
#define NUM_INVITE_MERGE_TOX 5
#include "run_auto_test.h"
#include "auto_test_support.h"
static void handle_conference_invite(
Tox *tox, uint32_t friend_number, Tox_Conference_Type type,
const uint8_t *cookie, size_t length, void *user_data)
{
State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
if (friend_number != -1) {
Tox_Err_Conference_Join err;
state->conference = tox_conference_join(tox, friend_number, cookie, length, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK,
"attempting to join the conference returned with an error: %d", err);
fprintf(stderr, "#%u accepted invite to conference %u\n", state->index, state->conference);
fprintf(stderr, "#%u accepted invite to conference %u\n", autotox->index, state->conference);
}
}
static void handle_conference_connected(
Tox *tox, uint32_t conference_number, void *user_data)
{
State *state = (State *)user_data;
fprintf(stderr, "#%u connected to conference %u\n", state->index, state->conference);
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
fprintf(stderr, "#%u connected to conference %u\n", autotox->index, state->conference);
state->connected = true;
}
static void iterate_alive(Tox **toxes, State *state)
{
for (uint32_t i = 0; i < NUM_INVITE_MERGE_TOX; i++) {
if (!state[i].alive) {
continue;
}
tox_iterate(toxes[i], &state[i]);
state[i].clock += ITERATION_INTERVAL;
}
c_sleep(20);
}
static void save(Tox **toxes, State *state, uint32_t n)
{
fprintf(stderr, "Saving #%u\n", state[n].index);
if (state[n].save_state != nullptr) {
free(state[n].save_state);
}
state[n].save_size = tox_get_savedata_size(toxes[n]);
state[n].save_state = (uint8_t *)malloc(state[n].save_size);
ck_assert_msg(state[n].save_state != nullptr, "malloc failed");
tox_get_savedata(toxes[n], state[n].save_state);
}
static void kill(Tox **toxes, State *state, uint32_t n)
{
fprintf(stderr, "Killing #%u\n", state[n].index);
state[n].alive = false;
tox_kill(toxes[n]);
}
static void reload(Tox **toxes, State *state, uint32_t n)
{
if (state[n].alive) {
state[n].alive = false;
tox_kill(toxes[n]);
}
fprintf(stderr, "Reloading #%u\n", state[n].index);
ck_assert(state[n].save_state != nullptr);
struct Tox_Options *const options = tox_options_new(nullptr);
ck_assert(options != nullptr);
tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_options_set_savedata_data(options, state[n].save_state, state[n].save_size);
toxes[n] = tox_new_log(options, nullptr, &state[n].index);
ck_assert(toxes[n] != nullptr);
tox_options_free(options);
set_mono_time_callback(toxes[n], &state[n]);
state[n].alive = true;
}
static void wait_connected(Tox **toxes, State *state, uint32_t n, uint32_t friendnumber)
static void wait_connected(AutoTox *autotoxes, AutoTox *autotox, uint32_t friendnumber)
{
do {
iterate_alive(toxes, state);
} while (tox_friend_get_connection_status(toxes[n], friendnumber, nullptr) == TOX_CONNECTION_NONE);
iterate_all_wait(NUM_INVITE_MERGE_TOX, autotoxes, ITERATION_INTERVAL);
} while (tox_friend_get_connection_status(autotox->tox, friendnumber, nullptr) == TOX_CONNECTION_NONE);
}
static void do_invite(Tox **toxes, State *state, uint32_t inviter, uint32_t invitee, uint32_t friendnum)
static void do_invite(AutoTox *autotoxes, AutoTox *inviter, AutoTox *invitee, uint32_t friendnum)
{
fprintf(stderr, "#%u inviting #%u\n", state[inviter].index, state[invitee].index);
fprintf(stderr, "#%u inviting #%u\n", inviter->index, invitee->index);
Tox_Err_Conference_Invite err;
tox_conference_invite(toxes[inviter], friendnum, state[inviter].conference, &err);
tox_conference_invite(inviter->tox, friendnum, ((State *)inviter->state)->conference, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK,
"#%u attempting to invite #%u (friendnumber %u) returned with an error: %d", state[inviter].index, state[invitee].index,
"#%u attempting to invite #%u (friendnumber %u) returned with an error: %d", inviter->index, invitee->index,
friendnum, err);
do {
iterate_alive(toxes, state);
} while (!state[invitee].connected);
iterate_all_wait(NUM_INVITE_MERGE_TOX, autotoxes, ITERATION_INTERVAL);
} while (!((State *)invitee->state)->connected);
}
static bool group_complete(Tox **toxes, State *state)
static bool group_complete(AutoTox *autotoxes)
{
int c = -1, size = 0;
for (int i = 0; i < NUM_INVITE_MERGE_TOX; i++) {
if (!state[i].alive) {
if (!autotoxes[i].alive) {
continue;
}
const int ct = tox_conference_peer_count(toxes[i], state[i].conference, nullptr);
const int ct = tox_conference_peer_count(autotoxes[i].tox, ((State *)autotoxes[i].state)->conference, nullptr);
if (c == -1) {
c = ct;
@ -143,100 +82,98 @@ static bool group_complete(Tox **toxes, State *state)
return (c == size);
}
static void wait_group_complete(Tox **toxes, State *state)
static void wait_group_complete(AutoTox *autotoxes)
{
do {
iterate_alive(toxes, state);
} while (!group_complete(toxes, state));
iterate_all_wait(NUM_INVITE_MERGE_TOX, autotoxes, ITERATION_INTERVAL);
} while (!group_complete(autotoxes));
}
static void conference_invite_merge_test(Tox **toxes, State *state)
static void conference_invite_merge_test(AutoTox *autotoxes)
{
// Test that an explicit invite between peers in different connected
// components will cause a split group to merge
for (int i = 0; i < NUM_INVITE_MERGE_TOX; i++) {
tox_callback_conference_invite(toxes[i], handle_conference_invite);
tox_callback_conference_connected(toxes[i], &handle_conference_connected);
state[i].alive = true;
state[i].save_state = nullptr;
tox_callback_conference_invite(autotoxes[i].tox, &handle_conference_invite);
tox_callback_conference_connected(autotoxes[i].tox, &handle_conference_connected);
}
State *state2 = (State *)autotoxes[2].state;
{
// Create new conference, tox 2 is the founder.
Tox_Err_Conference_New err;
state[2].conference = tox_conference_new(toxes[2], &err);
state[2].connected = true;
state2->conference = tox_conference_new(autotoxes[2].tox, &err);
state2->connected = true;
ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK,
"attempting to create a new conference returned with an error: %d", err);
fprintf(stderr, "Created conference: index=%u\n", state[2].conference);
fprintf(stderr, "Created conference: index=%u\n", state2->conference);
}
save(toxes, state, 2);
save_autotox(&autotoxes[2]);
do_invite(toxes, state, 2, 1, 0);
do_invite(toxes, state, 1, 0, 0);
do_invite(autotoxes, &autotoxes[2], &autotoxes[1], 0);
do_invite(autotoxes, &autotoxes[1], &autotoxes[0], 0);
save(toxes, state, 1);
kill(toxes, state, 1);
save_autotox(&autotoxes[1]);
kill_autotox(&autotoxes[1]);
do {
iterate_alive(toxes, state);
} while (tox_conference_peer_count(toxes[2], state[2].conference, nullptr) != 1);
iterate_all_wait(NUM_INVITE_MERGE_TOX, autotoxes, ITERATION_INTERVAL);
} while (tox_conference_peer_count(autotoxes[2].tox, state2->conference, nullptr) != 1);
do_invite(toxes, state, 2, 3, 1);
do_invite(toxes, state, 3, 4, 1);
do_invite(autotoxes, &autotoxes[2], &autotoxes[3], 1);
do_invite(autotoxes, &autotoxes[3], &autotoxes[4], 1);
kill(toxes, state, 2);
kill_autotox(&autotoxes[2]);
reload(toxes, state, 1);
reload(&autotoxes[1]);
uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
tox_self_get_public_key(toxes[1], public_key);
tox_friend_add_norequest(toxes[3], public_key, nullptr);
tox_self_get_public_key(toxes[3], public_key);
tox_friend_add_norequest(toxes[1], public_key, nullptr);
wait_connected(toxes, state, 1, 2);
tox_self_get_public_key(autotoxes[1].tox, public_key);
tox_friend_add_norequest(autotoxes[3].tox, public_key, nullptr);
tox_self_get_public_key(autotoxes[3].tox, public_key);
tox_friend_add_norequest(autotoxes[1].tox, public_key, nullptr);
wait_connected(autotoxes, &autotoxes[1], 2);
do_invite(toxes, state, 1, 3, 2);
do_invite(autotoxes, &autotoxes[1], &autotoxes[3], 2);
fprintf(stderr, "Waiting for group to merge\n");
wait_group_complete(toxes, state);
wait_group_complete(autotoxes);
fprintf(stderr, "Group merged\n");
reload(toxes, state, 2);
wait_connected(toxes, state, 2, 0);
do_invite(toxes, state, 2, 1, 0);
reload(&autotoxes[2]);
wait_connected(autotoxes, &autotoxes[2], 0);
do_invite(autotoxes, &autotoxes[2], &autotoxes[1], 0);
fprintf(stderr, "Waiting for #2 to rejoin\n");
wait_group_complete(toxes, state);
wait_group_complete(autotoxes);
kill(toxes, state, 2);
wait_group_complete(toxes, state);
reload(toxes, state, 2);
wait_connected(toxes, state, 2, 0);
wait_connected(toxes, state, 1, 1);
kill_autotox(&autotoxes[2]);
wait_group_complete(autotoxes);
reload(&autotoxes[2]);
wait_connected(autotoxes, &autotoxes[2], 0);
wait_connected(autotoxes, &autotoxes[1], 1);
do_invite(toxes, state, 1, 2, 1);
do_invite(autotoxes, &autotoxes[1], &autotoxes[2], 1);
fprintf(stderr, "Waiting for #2 to rejoin\n");
wait_group_complete(toxes, state);
for (int i = 0; i < NUM_INVITE_MERGE_TOX; i++) {
if (state[i].save_state != nullptr) {
free(state[i].save_state);
}
}
wait_group_complete(autotoxes);
}
int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, NUM_INVITE_MERGE_TOX, conference_invite_merge_test, true);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, NUM_INVITE_MERGE_TOX, conference_invite_merge_test, sizeof(State), &options);
return 0;
}

View File

@ -2,9 +2,6 @@
#include <stdint.h>
typedef struct State {
uint32_t index;
uint64_t clock;
bool self_online;
bool friend_online;
bool friend_in_group;
@ -13,38 +10,40 @@ typedef struct State {
uint32_t conference;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
static void handle_conference_invite(
Tox *tox, uint32_t friend_number, Tox_Conference_Type type,
const uint8_t *cookie, size_t length, void *user_data)
{
State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
fprintf(stderr, "handle_conference_invite(#%u, %u, %d, uint8_t[%u], _)\n",
state->index, friend_number, type, (unsigned)length);
fprintf(stderr, "tox%u joining conference\n", state->index);
autotox->index, friend_number, type, (unsigned)length);
fprintf(stderr, "tox%u joining conference\n", autotox->index);
Tox_Err_Conference_Join err;
state->conference = tox_conference_join(tox, friend_number, cookie, length, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK,
"attempting to join the conference returned with an error: %d", err);
fprintf(stderr, "tox%u joined conference %u\n", state->index, state->conference);
fprintf(stderr, "tox%u joined conference %u\n", autotox->index, state->conference);
state->joined = true;
}
static void handle_peer_list_changed(Tox *tox, uint32_t conference_number, void *user_data)
{
State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
fprintf(stderr, "handle_peer_list_changed(#%u, %u, _)\n",
state->index, conference_number);
autotox->index, conference_number);
Tox_Err_Conference_Peer_Query err;
uint32_t const count = tox_conference_peer_count(tox, conference_number, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_PEER_QUERY_OK,
"failed to get conference peer count: err = %d", err);
printf("tox%u has %u peers\n", state->index, count);
printf("tox%u has %u peers\n", autotox->index, count);
state->friend_in_group = count == 2;
}
@ -73,32 +72,36 @@ static void rebuild_peer_list(Tox *tox)
}
}
static void conference_peer_nick_test(Tox **toxes, State *state)
static void conference_peer_nick_test(AutoTox *autotoxes)
{
// Conference callbacks.
tox_callback_conference_invite(toxes[0], handle_conference_invite);
tox_callback_conference_invite(toxes[1], handle_conference_invite);
tox_callback_conference_peer_list_changed(toxes[0], handle_peer_list_changed);
tox_callback_conference_peer_list_changed(toxes[1], handle_peer_list_changed);
tox_callback_conference_invite(autotoxes[0].tox, handle_conference_invite);
tox_callback_conference_invite(autotoxes[1].tox, handle_conference_invite);
tox_callback_conference_peer_list_changed(autotoxes[0].tox, handle_peer_list_changed);
tox_callback_conference_peer_list_changed(autotoxes[1].tox, handle_peer_list_changed);
// Set the names of the toxes.
tox_self_set_name(toxes[0], (const uint8_t *)"test-tox-0", 10, nullptr);
tox_self_set_name(toxes[1], (const uint8_t *)"test-tox-1", 10, nullptr);
tox_self_set_name(autotoxes[0].tox, (const uint8_t *)"test-tox-0", 10, nullptr);
tox_self_set_name(autotoxes[1].tox, (const uint8_t *)"test-tox-1", 10, nullptr);
State *state[2];
state[0] = (State *)autotoxes[0].state;
state[1] = (State *)autotoxes[1].state;
{
// Create new conference, tox0 is the founder.
Tox_Err_Conference_New err;
state[0].conference = tox_conference_new(toxes[0], &err);
state[0].joined = true;
state[0]->conference = tox_conference_new(autotoxes[0].tox, &err);
state[0]->joined = true;
ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK,
"attempting to create a new conference returned with an error: %d", err);
fprintf(stderr, "Created conference: index=%u\n", state[0].conference);
fprintf(stderr, "Created conference: index=%u\n", state[0]->conference);
}
{
// Invite friend.
Tox_Err_Conference_Invite err;
tox_conference_invite(toxes[0], 0, state[0].conference, &err);
tox_conference_invite(autotoxes[0].tox, 0, state[0]->conference, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK,
"attempting to invite a friend returned with an error: %d", err);
fprintf(stderr, "tox0 invited tox1\n");
@ -107,17 +110,17 @@ static void conference_peer_nick_test(Tox **toxes, State *state)
fprintf(stderr, "Waiting for invitation to arrive and peers to be in the group\n");
do {
iterate_all_wait(2, toxes, state, ITERATION_INTERVAL);
} while (!state[0].joined || !state[1].joined || !state[0].friend_in_group || !state[1].friend_in_group);
iterate_all_wait(2, autotoxes, ITERATION_INTERVAL);
} while (!state[0]->joined || !state[1]->joined || !state[0]->friend_in_group || !state[1]->friend_in_group);
fprintf(stderr, "Running tox0, but not tox1, waiting for tox1 to drop out\n");
do {
iterate_all_wait(1, toxes, state, 1000);
iterate_all_wait(1, autotoxes, 1000);
// Rebuild peer list after every iteration.
rebuild_peer_list(toxes[0]);
} while (state[0].friend_in_group);
rebuild_peer_list(autotoxes[0].tox);
} while (state[0]->friend_in_group);
fprintf(stderr, "Invitations accepted\n");
}
@ -126,6 +129,9 @@ int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, 2, conference_peer_nick_test, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, 2, conference_peer_nick_test, sizeof(State), &options);
return 0;
}

View File

@ -19,35 +19,32 @@
#define NEW_NAME_FORMAT_STR "New #%4u"
typedef struct State {
uint32_t index;
uint64_t clock;
bool invited_next;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
static void handle_self_connection_status(
Tox *tox, Tox_Connection connection_status, void *user_data)
{
const State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
if (connection_status != TOX_CONNECTION_NONE) {
printf("tox #%u: is now connected\n", state->index);
printf("tox #%u: is now connected\n", autotox->index);
} else {
printf("tox #%u: is now disconnected\n", state->index);
printf("tox #%u: is now disconnected\n", autotox->index);
}
}
static void handle_friend_connection_status(
Tox *tox, uint32_t friendnumber, Tox_Connection connection_status, void *user_data)
{
const State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
if (connection_status != TOX_CONNECTION_NONE) {
printf("tox #%u: is now connected to friend %u\n", state->index, friendnumber);
printf("tox #%u: is now connected to friend %u\n", autotox->index, friendnumber);
} else {
printf("tox #%u: is now disconnected from friend %u\n", state->index, friendnumber);
printf("tox #%u: is now disconnected from friend %u\n", autotox->index, friendnumber);
}
}
@ -55,25 +52,26 @@ static void handle_conference_invite(
Tox *tox, uint32_t friendnumber, Tox_Conference_Type type,
const uint8_t *data, size_t length, void *user_data)
{
const State *state = (State *)user_data;
ck_assert_msg(type == TOX_CONFERENCE_TYPE_TEXT, "tox #%u: wrong conference type: %d", state->index, type);
const AutoTox *autotox = (AutoTox *)user_data;
ck_assert_msg(type == TOX_CONFERENCE_TYPE_TEXT, "tox #%u: wrong conference type: %d", autotox->index, type);
Tox_Err_Conference_Join err;
uint32_t g_num = tox_conference_join(tox, friendnumber, data, length, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "tox #%u: error joining group: %d", state->index, err);
ck_assert_msg(g_num == 0, "tox #%u: group number was not 0", state->index);
ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "tox #%u: error joining group: %d", autotox->index, err);
ck_assert_msg(g_num == 0, "tox #%u: group number was not 0", autotox->index);
// Try joining again. We should only be allowed to join once.
tox_conference_join(tox, friendnumber, data, length, &err);
ck_assert_msg(err != TOX_ERR_CONFERENCE_JOIN_OK,
"tox #%u: joining groupchat twice should be impossible.", state->index);
"tox #%u: joining groupchat twice should be impossible.", autotox->index);
}
static void handle_conference_connected(
Tox *tox, uint32_t conference_number, void *user_data)
{
State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
if (state->invited_next || tox_self_get_friend_list_size(tox) <= 1) {
return;
@ -81,8 +79,9 @@ static void handle_conference_connected(
Tox_Err_Conference_Invite err;
tox_conference_invite(tox, 1, 0, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox #%u failed to invite next friend: err = %d", state->index, err);
printf("tox #%u: invited next friend\n", state->index);
ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox #%u failed to invite next friend: err = %d", autotox->index,
err);
printf("tox #%u: invited next friend\n", autotox->index);
state->invited_next = true;
}
@ -97,7 +96,7 @@ static void handle_conference_message(
}
}
static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
static bool toxes_are_disconnected_from_group(uint32_t tox_count, AutoTox *autotoxes,
bool *disconnected)
{
uint32_t num_disconnected = 0;
@ -111,7 +110,7 @@ static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
continue;
}
if (tox_conference_peer_count(toxes[i], 0, nullptr) > tox_count - num_disconnected) {
if (tox_conference_peer_count(autotoxes[i].tox, 0, nullptr) > tox_count - num_disconnected) {
return false;
}
}
@ -119,7 +118,7 @@ static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
return true;
}
static void disconnect_toxes(uint32_t tox_count, Tox **toxes, State *state,
static void disconnect_toxes(uint32_t tox_count, AutoTox *autotoxes,
const bool *disconnect, const bool *exclude)
{
/* Fake a network outage for a set of peers D by iterating only the other
@ -137,22 +136,22 @@ static void disconnect_toxes(uint32_t tox_count, Tox **toxes, State *state,
do {
for (uint32_t i = 0; i < tox_count; ++i) {
if (!disconnect_now[i]) {
tox_iterate(toxes[i], &state[i]);
state[i].clock += 1000;
tox_iterate(autotoxes[i].tox, &autotoxes[i]);
autotoxes[i].clock += 1000;
}
}
c_sleep(20);
} while (!toxes_are_disconnected_from_group(tox_count, toxes, disconnect_now));
} while (!toxes_are_disconnected_from_group(tox_count, autotoxes, disconnect_now));
invert = !invert;
} while (invert);
}
static bool all_connected_to_group(uint32_t tox_count, Tox **toxes)
static bool all_connected_to_group(uint32_t tox_count, AutoTox *autotoxes)
{
for (uint32_t i = 0; i < tox_count; i++) {
if (tox_conference_peer_count(toxes[i], 0, nullptr) < tox_count) {
if (tox_conference_peer_count(autotoxes[i].tox, 0, nullptr) < tox_count) {
return false;
}
}
@ -160,11 +159,11 @@ static bool all_connected_to_group(uint32_t tox_count, Tox **toxes)
return true;
}
static bool names_propagated(uint32_t tox_count, Tox **toxes, State *state)
static bool names_propagated(uint32_t tox_count, AutoTox *autotoxes)
{
for (uint32_t i = 0; i < tox_count; ++i) {
for (uint32_t j = 0; j < tox_count; ++j) {
const size_t len = tox_conference_peer_get_name_size(toxes[i], 0, j, nullptr);
const size_t len = tox_conference_peer_get_name_size(autotoxes[i].tox, 0, j, nullptr);
if (len != NAMELEN) {
return false;
@ -191,7 +190,7 @@ static uint32_t random_false_index(bool *list, const uint32_t length)
return index;
}
static void run_conference_tests(Tox **toxes, State *state)
static void run_conference_tests(AutoTox *autotoxes)
{
/* disabling name change propagation check for now, as it occasionally
* fails due to disconnections too short to trigger freezing */
@ -204,9 +203,9 @@ static void run_conference_tests(Tox **toxes, State *state)
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
Tox_Err_Conference_Set_Max_Offline err;
tox_conference_set_max_offline(toxes[i], 0, max_frozen, &err);
tox_conference_set_max_offline(autotoxes[i].tox, 0, max_frozen, &err);
ck_assert_msg(err == TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK,
"tox #%u failed to set max offline: err = %d", state[i].index, err);
"tox #%u failed to set max offline: err = %d", autotoxes[i].index, err);
}
printf("letting random toxes timeout\n");
@ -221,9 +220,9 @@ static void run_conference_tests(Tox **toxes, State *state)
if (i < NUM_DISCONNECT / 2) {
restarting[disconnect] = true;
printf("Restarting #%u\n", state[disconnect].index);
printf("Restarting #%u\n", autotoxes[disconnect].index);
} else {
printf("Disconnecting #%u\n", state[disconnect].index);
printf("Disconnecting #%u\n", autotoxes[disconnect].index);
}
}
@ -232,16 +231,16 @@ static void run_conference_tests(Tox **toxes, State *state)
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
if (restarting[i]) {
save_size[i] = tox_get_savedata_size(toxes[i]);
save_size[i] = tox_get_savedata_size(autotoxes[i].tox);
ck_assert_msg(save_size[i] != 0, "save is invalid size %u", (unsigned)save_size[i]);
save[i] = (uint8_t *)malloc(save_size[i]);
ck_assert_msg(save[i] != nullptr, "malloc failed");
tox_get_savedata(toxes[i], save[i]);
tox_kill(toxes[i]);
tox_get_savedata(autotoxes[i].tox, save[i]);
tox_kill(autotoxes[i].tox);
}
}
disconnect_toxes(NUM_GROUP_TOX, toxes, state, disconnected, restarting);
disconnect_toxes(NUM_GROUP_TOX, autotoxes, disconnected, restarting);
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
if (restarting[i]) {
@ -249,13 +248,13 @@ static void run_conference_tests(Tox **toxes, State *state)
ck_assert(options != nullptr);
tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_options_set_savedata_data(options, save[i], save_size[i]);
toxes[i] = tox_new_log(options, nullptr, &state[i].index);
ck_assert(toxes[i] != nullptr);
autotoxes[i].tox = tox_new_log(options, nullptr, &autotoxes[i].index);
ck_assert(autotoxes[i].tox != nullptr);
tox_options_free(options);
free(save[i]);
set_mono_time_callback(toxes[i], &state[i]);
tox_conference_set_max_offline(toxes[i], 0, max_frozen, nullptr);
set_mono_time_callback(&autotoxes[i]);
tox_conference_set_max_offline(autotoxes[i].tox, 0, max_frozen, nullptr);
}
}
@ -264,43 +263,43 @@ static void run_conference_tests(Tox **toxes, State *state)
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
char name[NAMELEN + 1];
snprintf(name, NAMELEN + 1, NEW_NAME_FORMAT_STR, state[i].index);
tox_self_set_name(toxes[i], (const uint8_t *)name, NAMELEN, nullptr);
snprintf(name, NAMELEN + 1, NEW_NAME_FORMAT_STR, autotoxes[i].index);
tox_self_set_name(autotoxes[i].tox, (const uint8_t *)name, NAMELEN, nullptr);
}
}
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
const uint32_t num_frozen = tox_conference_offline_peer_count(toxes[i], 0, nullptr);
const uint32_t num_frozen = tox_conference_offline_peer_count(autotoxes[i].tox, 0, nullptr);
ck_assert_msg(num_frozen <= max_frozen,
"tox #%u has too many offline peers: %u\n",
state[i].index, num_frozen);
autotoxes[i].index, num_frozen);
}
printf("reconnecting toxes\n");
do {
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
} while (!all_connected_to_group(NUM_GROUP_TOX, toxes));
iterate_all_wait(NUM_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
} while (!all_connected_to_group(NUM_GROUP_TOX, autotoxes));
printf("running conference tests\n");
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
tox_callback_conference_message(toxes[i], &handle_conference_message);
tox_callback_conference_message(autotoxes[i].tox, &handle_conference_message);
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(NUM_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
}
Tox_Err_Conference_Send_Message err;
ck_assert_msg(
tox_conference_send_message(
toxes[random_u32() % NUM_GROUP_TOX], 0, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)GROUP_MESSAGE,
autotoxes[random_u32() % NUM_GROUP_TOX].tox, 0, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)GROUP_MESSAGE,
sizeof(GROUP_MESSAGE) - 1, &err) != 0, "failed to send group message");
ck_assert_msg(
err == TOX_ERR_CONFERENCE_SEND_MESSAGE_OK, "failed to send group message");
num_recv = 0;
for (uint8_t j = 0; j < NUM_GROUP_TOX * 2; ++j) {
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(NUM_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
}
ck_assert_msg(num_recv == NUM_GROUP_TOX, "failed to recv group messages");
@ -309,23 +308,23 @@ static void run_conference_tests(Tox **toxes, State *state)
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
for (uint32_t j = 0; j < NUM_GROUP_TOX; ++j) {
uint8_t name[NAMELEN];
tox_conference_peer_get_name(toxes[i], 0, j, name, nullptr);
tox_conference_peer_get_name(autotoxes[i].tox, 0, j, name, nullptr);
/* Note the toxes will have been reordered */
ck_assert_msg(memcmp(name, "New", 3) == 0,
"name of #%u according to #%u not updated", state[j].index, state[i].index);
"name of #%u according to #%u not updated", autotoxes[j].index, autotoxes[i].index);
}
}
}
for (uint32_t k = NUM_GROUP_TOX; k != 0 ; --k) {
tox_conference_delete(toxes[k - 1], 0, nullptr);
tox_conference_delete(autotoxes[k - 1].tox, 0, nullptr);
for (uint8_t j = 0; j < 10 || j < NUM_GROUP_TOX; ++j) {
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(NUM_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
}
for (uint32_t i = 0; i < k - 1; ++i) {
uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, nullptr);
uint32_t peer_count = tox_conference_peer_count(autotoxes[i].tox, 0, nullptr);
ck_assert_msg(peer_count == (k - 1), "\n\tBad number of group peers (post check)."
"\n\t\t\tExpected: %u but tox_instance(%u) only has: %u\n\n",
k - 1, i, (unsigned)peer_count);
@ -333,26 +332,27 @@ static void run_conference_tests(Tox **toxes, State *state)
}
}
static void test_many_group(Tox **toxes, State *state)
static void test_many_group(AutoTox *autotoxes)
{
const time_t test_start_time = time(nullptr);
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
tox_callback_self_connection_status(toxes[i], &handle_self_connection_status);
tox_callback_friend_connection_status(toxes[i], &handle_friend_connection_status);
tox_callback_conference_invite(toxes[i], &handle_conference_invite);
tox_callback_conference_connected(toxes[i], &handle_conference_connected);
tox_callback_self_connection_status(autotoxes[i].tox, &handle_self_connection_status);
tox_callback_friend_connection_status(autotoxes[i].tox, &handle_friend_connection_status);
tox_callback_conference_invite(autotoxes[i].tox, &handle_conference_invite);
tox_callback_conference_connected(autotoxes[i].tox, &handle_conference_connected);
char name[NAMELEN + 1];
snprintf(name, NAMELEN + 1, NAME_FORMAT_STR, state[i].index);
tox_self_set_name(toxes[i], (const uint8_t *)name, NAMELEN, nullptr);
snprintf(name, NAMELEN + 1, NAME_FORMAT_STR, autotoxes[i].index);
tox_self_set_name(autotoxes[i].tox, (const uint8_t *)name, NAMELEN, nullptr);
}
ck_assert_msg(tox_conference_new(toxes[0], nullptr) != UINT32_MAX, "failed to create group");
printf("tox #%u: inviting its first friend\n", state[0].index);
ck_assert_msg(tox_conference_invite(toxes[0], 0, 0, nullptr) != 0, "failed to invite friend");
state[0].invited_next = true;
ck_assert_msg(tox_conference_set_title(toxes[0], 0, (const uint8_t *)"Gentoo", sizeof("Gentoo") - 1, nullptr) != 0,
ck_assert_msg(tox_conference_new(autotoxes[0].tox, nullptr) != UINT32_MAX, "failed to create group");
printf("tox #%u: inviting its first friend\n", autotoxes[0].index);
ck_assert_msg(tox_conference_invite(autotoxes[0].tox, 0, 0, nullptr) != 0, "failed to invite friend");
((State *)autotoxes[0].state)->invited_next = true;
ck_assert_msg(tox_conference_set_title(autotoxes[0].tox, 0, (const uint8_t *)"Gentoo", sizeof("Gentoo") - 1,
nullptr) != 0,
"failed to set group title");
@ -360,16 +360,16 @@ static void test_many_group(Tox **toxes, State *state)
uint32_t invited_count = 0;
do {
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(NUM_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
invited_count = 0;
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
invited_count += state[i].invited_next;
invited_count += ((State *)autotoxes[i].state)->invited_next;
}
} while (invited_count != NUM_GROUP_TOX - 1);
uint64_t pregroup_clock = state[0].clock;
uint64_t pregroup_clock = autotoxes[0].clock;
printf("waiting for all toxes to be in the group\n");
uint32_t fully_connected_count = 0;
@ -377,11 +377,11 @@ static void test_many_group(Tox **toxes, State *state)
fully_connected_count = 0;
printf("current peer counts: [");
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(NUM_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
Tox_Err_Conference_Peer_Query err;
uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, &err);
uint32_t peer_count = tox_conference_peer_count(autotoxes[i].tox, 0, &err);
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
peer_count = 0;
@ -401,28 +401,28 @@ static void test_many_group(Tox **toxes, State *state)
} while (fully_connected_count != NUM_GROUP_TOX);
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, nullptr);
uint32_t peer_count = tox_conference_peer_count(autotoxes[i].tox, 0, nullptr);
ck_assert_msg(peer_count == NUM_GROUP_TOX, "\n\tBad number of group peers (pre check)."
"\n\t\t\tExpected: %d but tox_instance(%u) only has: %u\n\n",
NUM_GROUP_TOX, i, (unsigned)peer_count);
uint8_t title[2048];
size_t ret = tox_conference_get_title_size(toxes[i], 0, nullptr);
size_t ret = tox_conference_get_title_size(autotoxes[i].tox, 0, nullptr);
ck_assert_msg(ret == sizeof("Gentoo") - 1, "Wrong title length");
tox_conference_get_title(toxes[i], 0, title, nullptr);
tox_conference_get_title(autotoxes[i].tox, 0, title, nullptr);
ck_assert_msg(memcmp("Gentoo", title, ret) == 0, "Wrong title");
}
printf("waiting for names to propagate\n");
do {
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
} while (!names_propagated(NUM_GROUP_TOX, toxes, state));
iterate_all_wait(NUM_GROUP_TOX, autotoxes, ITERATION_INTERVAL);
} while (!names_propagated(NUM_GROUP_TOX, autotoxes));
printf("group connected, took %d seconds\n", (int)((state[0].clock - pregroup_clock) / 1000));
printf("group connected, took %d seconds\n", (int)((autotoxes[0].clock - pregroup_clock) / 1000));
run_conference_tests(toxes, state);
run_conference_tests(autotoxes);
printf("test_many_group succeeded, took %d seconds\n", (int)(time(nullptr) - test_start_time));
}
@ -431,6 +431,9 @@ int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, NUM_GROUP_TOX, test_many_group, true);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, NUM_GROUP_TOX, test_many_group, sizeof(State), &options);
return 0;
}

View File

@ -7,14 +7,9 @@
#include <stdint.h>
typedef struct State {
uint32_t index;
uint64_t clock;
} State;
#include "auto_test_support.h"
#include "run_auto_test.h"
static void friend_connection_test(Tox **toxes, State *state)
static void friend_connection_test(AutoTox *toxes)
{
// Nothing to do here. When copying this test, add test-specific code here.
}
@ -23,6 +18,9 @@ int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, 2, friend_connection_test, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, 2, friend_connection_test, 0, &options);
return 0;
}

View File

@ -13,20 +13,18 @@
#include "check_compat.h"
typedef struct State {
uint32_t index;
uint64_t clock;
bool custom_packet_received;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
#define LOSSLESS_PACKET_FILLER 160
static void handle_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
void *user_data)
{
State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
uint8_t cmp_packet[TOX_MAX_CUSTOM_PACKET_SIZE];
memset(cmp_packet, LOSSLESS_PACKET_FILLER, sizeof(cmp_packet));
@ -36,27 +34,31 @@ static void handle_lossless_packet(Tox *tox, uint32_t friend_number, const uint8
}
}
static void test_lossless_packet(Tox **toxes, State *state)
static void test_lossless_packet(AutoTox *autotoxes)
{
tox_callback_friend_lossless_packet(toxes[1], &handle_lossless_packet);
tox_callback_friend_lossless_packet(autotoxes[1].tox, &handle_lossless_packet);
uint8_t packet[TOX_MAX_CUSTOM_PACKET_SIZE + 1];
memset(packet, LOSSLESS_PACKET_FILLER, sizeof(packet));
bool ret = tox_friend_send_lossless_packet(toxes[0], 0, packet, sizeof(packet), nullptr);
bool ret = tox_friend_send_lossless_packet(autotoxes[0].tox, 0, packet, sizeof(packet), nullptr);
ck_assert_msg(ret == false, "should not be able to send custom packets this big %i", ret);
ret = tox_friend_send_lossless_packet(toxes[0], 0, packet, TOX_MAX_CUSTOM_PACKET_SIZE, nullptr);
ret = tox_friend_send_lossless_packet(autotoxes[0].tox, 0, packet, TOX_MAX_CUSTOM_PACKET_SIZE, nullptr);
ck_assert_msg(ret == true, "tox_friend_send_lossless_packet fail %i", ret);
do {
iterate_all_wait(2, toxes, state, ITERATION_INTERVAL);
} while (!state[1].custom_packet_received);
iterate_all_wait(2, autotoxes, ITERATION_INTERVAL);
} while (!((State *)autotoxes[1].state)->custom_packet_received);
}
int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, 2, test_lossless_packet, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, 2, test_lossless_packet, sizeof(State), &options);
return 0;
}

View File

@ -11,13 +11,10 @@
#include "check_compat.h"
typedef struct State {
uint32_t index;
uint64_t clock;
bool custom_packet_received;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
#define LOSSY_PACKET_FILLER 200
@ -27,32 +24,37 @@ static void handle_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t
memset(cmp_packet, LOSSY_PACKET_FILLER, sizeof(cmp_packet));
if (length == TOX_MAX_CUSTOM_PACKET_SIZE && memcmp(data, cmp_packet, sizeof(cmp_packet)) == 0) {
State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
state->custom_packet_received = true;
}
}
static void test_lossy_packet(Tox **toxes, State *state)
static void test_lossy_packet(AutoTox *autotoxes)
{
tox_callback_friend_lossy_packet(toxes[1], &handle_lossy_packet);
tox_callback_friend_lossy_packet(autotoxes[1].tox, &handle_lossy_packet);
uint8_t packet[TOX_MAX_CUSTOM_PACKET_SIZE + 1];
memset(packet, LOSSY_PACKET_FILLER, sizeof(packet));
bool ret = tox_friend_send_lossy_packet(toxes[0], 0, packet, sizeof(packet), nullptr);
bool ret = tox_friend_send_lossy_packet(autotoxes[0].tox, 0, packet, sizeof(packet), nullptr);
ck_assert_msg(ret == false, "should not be able to send custom packets this big %i", ret);
ret = tox_friend_send_lossy_packet(toxes[0], 0, packet, TOX_MAX_CUSTOM_PACKET_SIZE, nullptr);
ret = tox_friend_send_lossy_packet(autotoxes[0].tox, 0, packet, TOX_MAX_CUSTOM_PACKET_SIZE, nullptr);
ck_assert_msg(ret == true, "tox_friend_send_lossy_packet fail %i", ret);
do {
iterate_all_wait(2, toxes, state, ITERATION_INTERVAL);
} while (!state[1].custom_packet_received);
iterate_all_wait(2, autotoxes, ITERATION_INTERVAL);
} while (!((State *)autotoxes[1].state)->custom_packet_received);
}
int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, 2, test_lossy_packet, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, 2, test_lossy_packet, sizeof(State), &options);
return 0;
}

View File

@ -4,26 +4,24 @@
#include <stdint.h>
typedef struct State {
uint32_t index;
uint64_t clock;
uint32_t recv_count;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
#define NUM_MSGS 40000
static void handle_friend_message(Tox *tox, uint32_t friend_number, Tox_Message_Type type,
const uint8_t *message, size_t length, void *user_data)
{
State *state = (State *)user_data;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
state->recv_count++;
}
static void net_crypto_overflow_test(Tox **toxes, State *state)
static void net_crypto_overflow_test(AutoTox *autotoxes)
{
tox_callback_friend_message(toxes[0], handle_friend_message);
tox_callback_friend_message(autotoxes[0].tox, handle_friend_message);
printf("sending many messages to tox0\n");
@ -33,7 +31,7 @@ static void net_crypto_overflow_test(Tox **toxes, State *state)
snprintf((char *)message, sizeof(message), "%u-%u", tox_index, i);
Tox_Err_Friend_Send_Message err;
tox_friend_send_message(toxes[tox_index], 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof message, &err);
tox_friend_send_message(autotoxes[tox_index].tox, 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof message, &err);
if (err == TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ) {
printf("tox%u sent %u messages to friend 0\n", tox_index, i);
@ -48,16 +46,19 @@ static void net_crypto_overflow_test(Tox **toxes, State *state)
// TODO(iphydf): Wait until all messages have arrived. Currently, not all
// messages arrive, so this test would always fail.
for (uint32_t i = 0; i < 200; i++) {
iterate_all_wait(3, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(3, autotoxes, ITERATION_INTERVAL);
}
printf("tox%u received %u messages\n", state[0].index, state[0].recv_count);
printf("tox%u received %u messages\n", autotoxes[0].index, ((State *)autotoxes[0].state)->recv_count);
}
int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, 3, net_crypto_overflow_test, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, 3, net_crypto_overflow_test, sizeof(State), &options);
return 0;
}

View File

@ -3,23 +3,18 @@
#include <stdint.h>
typedef struct State {
uint32_t index;
uint64_t clock;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
#define NUM_MSGS 40000
static void net_crypto_overflow_test(Tox **toxes, State *state)
static void net_crypto_overflow_test(AutoTox *autotoxes)
{
const uint8_t message[] = {0};
bool errored = false;
for (uint32_t i = 0; i < NUM_MSGS; i++) {
Tox_Err_Friend_Send_Message err;
tox_friend_send_message(toxes[0], 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof message, &err);
tox_friend_send_message(autotoxes[0].tox, 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof message, &err);
if (err != TOX_ERR_FRIEND_SEND_MESSAGE_OK) {
errored = true;
@ -43,6 +38,9 @@ int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, 2, net_crypto_overflow_test, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, 2, net_crypto_overflow_test, 0, &options);
return 0;
}

View File

@ -18,20 +18,15 @@
#define TOX_COUNT 2
#define RECONNECT_TIME_MAX (FRIEND_CONNECTION_TIMEOUT + 3)
typedef struct State {
uint32_t index;
uint64_t clock;
} State;
#include "auto_test_support.h"
#include "run_auto_test.h"
static uint32_t tox_connected_count(uint32_t tox_count, Tox **toxes, State *state, uint32_t index)
static uint32_t tox_connected_count(uint32_t tox_count, AutoTox *autotoxes, uint32_t index)
{
const size_t friend_count = tox_self_get_friend_list_size(toxes[index]);
const size_t friend_count = tox_self_get_friend_list_size(autotoxes[index].tox);
uint32_t connected_count = 0;
for (size_t j = 0; j < friend_count; j++) {
if (tox_friend_get_connection_status(toxes[index], j, nullptr) != TOX_CONNECTION_NONE) {
if (tox_friend_get_connection_status(autotoxes[index].tox, j, nullptr) != TOX_CONNECTION_NONE) {
++connected_count;
}
}
@ -39,14 +34,14 @@ static uint32_t tox_connected_count(uint32_t tox_count, Tox **toxes, State *stat
return connected_count;
}
static bool all_disconnected_from(uint32_t tox_count, Tox **toxes, State *state, uint32_t index)
static bool all_disconnected_from(uint32_t tox_count, AutoTox *autotoxes, uint32_t index)
{
for (uint32_t i = 0; i < tox_count; i++) {
if (i == index) {
continue;
}
if (tox_connected_count(tox_count, toxes, state, i) >= tox_count - 1) {
if (tox_connected_count(tox_count, autotoxes, i) >= tox_count - 1) {
return false;
}
}
@ -54,39 +49,39 @@ static bool all_disconnected_from(uint32_t tox_count, Tox **toxes, State *state,
return true;
}
static void test_reconnect(Tox **toxes, State *state)
static void test_reconnect(AutoTox *autotoxes)
{
const time_t test_start_time = time(nullptr);
printf("letting connections settle\n");
do {
iterate_all_wait(TOX_COUNT, toxes, state, ITERATION_INTERVAL);
iterate_all_wait(TOX_COUNT, autotoxes, ITERATION_INTERVAL);
} while (time(nullptr) - test_start_time < 2);
uint16_t disconnect = random_u16() % TOX_COUNT;
printf("disconnecting #%u\n", state[disconnect].index);
printf("disconnecting #%u\n", autotoxes[disconnect].index);
do {
for (uint16_t i = 0; i < TOX_COUNT; ++i) {
if (i != disconnect) {
tox_iterate(toxes[i], &state[i]);
state[i].clock += 1000;
tox_iterate(autotoxes[i].tox, &autotoxes[i]);
autotoxes[i].clock += 1000;
}
}
c_sleep(20);
} while (!all_disconnected_from(TOX_COUNT, toxes, state, disconnect));
} while (!all_disconnected_from(TOX_COUNT, autotoxes, disconnect));
const uint64_t reconnect_start_time = state[0].clock;
const uint64_t reconnect_start_time = autotoxes[0].clock;
printf("reconnecting\n");
do {
iterate_all_wait(TOX_COUNT, toxes, state, ITERATION_INTERVAL);
} while (!all_friends_connected(TOX_COUNT, toxes));
iterate_all_wait(TOX_COUNT, autotoxes, ITERATION_INTERVAL);
} while (!all_friends_connected(TOX_COUNT, autotoxes));
const uint64_t reconnect_time = state[0].clock - reconnect_start_time;
const uint64_t reconnect_time = autotoxes[0].clock - reconnect_start_time;
ck_assert_msg(reconnect_time <= RECONNECT_TIME_MAX * 1000, "reconnection took %d seconds; expected at most %d seconds",
(int)(reconnect_time / 1000), RECONNECT_TIME_MAX);
@ -97,6 +92,9 @@ int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, TOX_COUNT, test_reconnect, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, TOX_COUNT, test_reconnect, 0, &options);
return 0;
}

View File

@ -1,232 +0,0 @@
#include <stdlib.h> // calloc, free
#include "check_compat.h"
#include "../testing/misc_tools.h"
#include "../toxcore/Messenger.h"
#include "../toxcore/mono_time.h"
// List of live bootstrap nodes. These nodes should have TCP server enabled.
static const struct BootstrapNodes {
const char *ip;
uint16_t port;
const uint8_t key[32];
} BootstrapNodes[] = {
#ifndef USE_TEST_NETWORK
{
"tox.abilinski.com", 33445,
0x10, 0xC0, 0x0E, 0xB2, 0x50, 0xC3, 0x23, 0x3E,
0x34, 0x3E, 0x2A, 0xEB, 0xA0, 0x71, 0x15, 0xA5,
0xC2, 0x89, 0x20, 0xE9, 0xC8, 0xD2, 0x94, 0x92,
0xF6, 0xD0, 0x0B, 0x29, 0x04, 0x9E, 0xDC, 0x7E,
},
{
"tox.initramfs.io", 33445,
0x02, 0x80, 0x7C, 0xF4, 0xF8, 0xBB, 0x8F, 0xB3,
0x90, 0xCC, 0x37, 0x94, 0xBD, 0xF1, 0xE8, 0x44,
0x9E, 0x9A, 0x83, 0x92, 0xC5, 0xD3, 0xF2, 0x20,
0x00, 0x19, 0xDA, 0x9F, 0x1E, 0x81, 0x2E, 0x46,
},
{
"tox.plastiras.org", 33445,
0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F,
0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33,
0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED,
0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25,
},
{
"tox.novg.net", 33445,
0xD5, 0x27, 0xE5, 0x84, 0x7F, 0x83, 0x30, 0xD6,
0x28, 0xDA, 0xB1, 0x81, 0x4F, 0x0A, 0x42, 0x2F,
0x6D, 0xC9, 0xD0, 0xA3, 0x00, 0xE6, 0xC3, 0x57,
0x63, 0x4E, 0xE2, 0xDA, 0x88, 0xC3, 0x54, 0x63,
},
#else
{
"172.93.52.70", 33445,
0x79, 0xCA, 0xDA, 0x49, 0x74, 0xB0, 0x92, 0x6F,
0x28, 0x6F, 0x02, 0x5C, 0xD5, 0xFF, 0xDF, 0x3E,
0x65, 0x4A, 0x37, 0x58, 0xC5, 0x3E, 0x02, 0x73,
0xEC, 0xFC, 0x4D, 0x12, 0xC2, 0x1D, 0xCA, 0x48,
},
#endif // USE_TEST_NETWORK
{ nullptr, 0, 0 },
};
static void bootstrap_toxes_live_network(Tox **toxes, uint32_t tox_count, bool enable_tcp)
{
for (size_t i = 0; i < tox_count; ++i) {
for (size_t j = 0; BootstrapNodes[j].ip != nullptr; ++j) {
const char *ip = BootstrapNodes[j].ip;
uint16_t port = BootstrapNodes[j].port;
const uint8_t *key = BootstrapNodes[j].key;
Tox_Err_Bootstrap err;
tox_bootstrap(toxes[i], ip, port, key, &err);
if (err != TOX_ERR_BOOTSTRAP_OK) {
fprintf(stderr, "Failed to bootstrap node %zu (%s): error %d\n", j, ip, err);
}
if (enable_tcp) {
tox_add_tcp_relay(toxes[i], ip, port, key, &err);
if (err != TOX_ERR_BOOTSTRAP_OK) {
fprintf(stderr, "Failed to add TCP relay %zu (%s): error %d\n", j, ip, err);
}
}
}
}
}
static bool all_connected(uint32_t tox_count, Tox **toxes)
{
for (uint32_t i = 0; i < tox_count; i++) {
if (tox_self_get_connection_status(toxes[i]) == TOX_CONNECTION_NONE) {
return false;
}
}
return true;
}
static bool all_friends_connected(uint32_t tox_count, Tox **toxes)
{
for (uint32_t i = 0; i < tox_count; i++) {
const size_t friend_count = tox_self_get_friend_list_size(toxes[i]);
for (size_t j = 0; j < friend_count; j++) {
if (tox_friend_get_connection_status(toxes[i], j, nullptr) == TOX_CONNECTION_NONE) {
return false;
}
}
}
return true;
}
static void iterate_all_wait(uint32_t tox_count, Tox **toxes, State *state, uint32_t wait)
{
for (uint32_t i = 0; i < tox_count; i++) {
tox_iterate(toxes[i], &state[i]);
state[i].clock += wait;
}
/* Also actually sleep a little, to allow for local network processing */
c_sleep(5);
}
static uint64_t get_state_clock_callback(Mono_Time *mono_time, void *user_data)
{
const State *state = (const State *)user_data;
return state->clock;
}
static void set_mono_time_callback(Tox *tox, State *state)
{
// TODO(iphydf): Don't rely on toxcore internals.
Mono_Time *mono_time = ((Messenger *)tox)->mono_time;
state->clock = current_time_monotonic(mono_time);
mono_time_set_current_time_callback(mono_time, get_state_clock_callback, state);
}
static void add_friend(uint32_t i, uint32_t j, Tox **toxes)
{
uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
tox_self_get_public_key(toxes[j], public_key);
Tox_Err_Friend_Add err;
tox_friend_add_norequest(toxes[i], public_key, &err);
ck_assert(err == TOX_ERR_FRIEND_ADD_OK);
}
static void build_friend_graph(uint32_t tox_count, bool chain, Tox **toxes)
{
if (chain) {
printf("each tox adds adjacent toxes as friends\n");
for (uint32_t i = 0; i < tox_count; i++) {
for (uint32_t j = i - 1; j != i + 3; j += 2) {
if (j >= tox_count) {
continue;
}
add_friend(i, j, toxes);
}
}
} else {
printf("toxes all add each other as friends\n");
for (uint32_t i = 0; i < tox_count; i++) {
for (uint32_t j = 0; j < tox_count; j++) {
if (i != j) {
add_friend(i, j, toxes);
}
}
}
}
}
static void wait_friend_connections(uint32_t tox_count, Tox **toxes, State *state)
{
do {
iterate_all_wait(tox_count, toxes, state, ITERATION_INTERVAL);
} while (!all_connected(tox_count, toxes));
printf("toxes are online\n");
do {
iterate_all_wait(tox_count, toxes, state, ITERATION_INTERVAL);
} while (!all_friends_connected(tox_count, toxes));
printf("tox clients connected\n");
}
static void run_auto_test(struct Tox_Options *options, uint32_t tox_count, void test(Tox **toxes, State *state),
bool chain)
{
printf("initialising %u toxes\n", tox_count);
Tox **toxes = (Tox **)calloc(tox_count, sizeof(Tox *));
State *state = (State *)calloc(tox_count, sizeof(State));
ck_assert(toxes != nullptr);
ck_assert(state != nullptr);
for (uint32_t i = 0; i < tox_count; i++) {
state[i].index = i;
toxes[i] = tox_new_log(options, nullptr, &state[i].index);
ck_assert_msg(toxes[i], "failed to create %u tox instances", i + 1);
set_mono_time_callback(toxes[i], &state[i]);
}
build_friend_graph(tox_count, chain, toxes);
const bool udp_enabled = options != nullptr ? tox_options_get_udp_enabled(options) : true;
Tox_Err_Bootstrap err;
if (udp_enabled) {
printf("bootstrapping all toxes off toxes[0]\n");
uint8_t dht_key[TOX_PUBLIC_KEY_SIZE];
tox_self_get_dht_id(toxes[0], dht_key);
const uint16_t dht_port = tox_self_get_udp_port(toxes[0], nullptr);
for (uint32_t i = 1; i < tox_count; i++) {
tox_bootstrap(toxes[i], "localhost", dht_port, dht_key, &err);
ck_assert(err == TOX_ERR_BOOTSTRAP_OK);
}
} else {
printf("bootstrapping all toxes to tcp relays\n");
bootstrap_toxes_live_network(toxes, tox_count, true);
}
wait_friend_connections(tox_count, toxes, state);
test(toxes, state);
for (uint32_t i = 0; i < tox_count; i++) {
tox_kill(toxes[i]);
}
free(state);
free(toxes);
}

View File

@ -6,21 +6,19 @@
#include <string.h>
typedef struct State {
uint32_t index;
uint64_t clock;
bool message_received;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
#define MESSAGE_FILLER 'G'
static void message_callback(
Tox *m, uint32_t friendnumber, Tox_Message_Type type,
const uint8_t *string, size_t length, void *userdata)
const uint8_t *string, size_t length, void *user_data)
{
State *state = (State *)userdata;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
if (type != TOX_MESSAGE_TYPE_NORMAL) {
ck_abort_msg("Bad type");
@ -34,29 +32,32 @@ static void message_callback(
}
}
static void send_message_test(Tox **toxes, State *state)
static void send_message_test(AutoTox *autotoxes)
{
tox_callback_friend_message(toxes[1], &message_callback);
tox_callback_friend_message(autotoxes[1].tox, &message_callback);
uint8_t msgs[TOX_MAX_MESSAGE_LENGTH + 1];
memset(msgs, MESSAGE_FILLER, sizeof(msgs));
Tox_Err_Friend_Send_Message errm;
tox_friend_send_message(toxes[0], 0, TOX_MESSAGE_TYPE_NORMAL, msgs, TOX_MAX_MESSAGE_LENGTH + 1, &errm);
tox_friend_send_message(autotoxes[0].tox, 0, TOX_MESSAGE_TYPE_NORMAL, msgs, TOX_MAX_MESSAGE_LENGTH + 1, &errm);
ck_assert_msg(errm == TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG, "TOX_MAX_MESSAGE_LENGTH is too small? error=%d", errm);
tox_friend_send_message(toxes[0], 0, TOX_MESSAGE_TYPE_NORMAL, msgs, TOX_MAX_MESSAGE_LENGTH, &errm);
tox_friend_send_message(autotoxes[0].tox, 0, TOX_MESSAGE_TYPE_NORMAL, msgs, TOX_MAX_MESSAGE_LENGTH, &errm);
ck_assert_msg(errm == TOX_ERR_FRIEND_SEND_MESSAGE_OK, "TOX_MAX_MESSAGE_LENGTH is too big? error=%d", errm);
do {
iterate_all_wait(2, toxes, state, ITERATION_INTERVAL);
} while (!state[1].message_received);
iterate_all_wait(2, autotoxes, ITERATION_INTERVAL);
} while (!((State *)autotoxes[1].state)->message_received);
}
int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, 2, send_message_test, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, 2, send_message_test, sizeof(State), &options);
return 0;
}

View File

@ -3,12 +3,7 @@
#include "../testing/misc_tools.h"
#include "check_compat.h"
typedef struct State {
uint32_t index;
uint64_t clock;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
int main(void)
{
@ -19,7 +14,7 @@ int main(void)
Tox *tox_tcp = tox_new_log(opts, nullptr, nullptr);
tox_options_free(opts);
bootstrap_toxes_live_network(&tox_tcp, 1, true);
bootstrap_tox_live_network(tox_tcp, true);
printf("Waiting for connection");
@ -38,7 +33,5 @@ int main(void)
tox_kill(tox_tcp);
(void)run_auto_test;
return 0;
}

View File

@ -12,40 +12,39 @@
#include "check_compat.h"
typedef struct State {
uint32_t index;
uint64_t clock;
bool friend_is_typing;
} State;
#include "run_auto_test.h"
#include "auto_test_support.h"
static void typing_callback(Tox *m, uint32_t friendnumber, bool typing, void *userdata)
static void typing_callback(Tox *m, uint32_t friendnumber, bool typing, void *user_data)
{
State *state = (State *)userdata;
const AutoTox *autotox = (AutoTox *)user_data;
State *state = (State *)autotox->state;
state->friend_is_typing = typing;
}
static void test_typing(Tox **toxes, State *state)
static void test_typing(AutoTox *autotoxes)
{
time_t cur_time = time(nullptr);
tox_callback_friend_typing(toxes[1], &typing_callback);
tox_self_set_typing(toxes[0], 0, true, nullptr);
tox_callback_friend_typing(autotoxes[1].tox, &typing_callback);
tox_self_set_typing(autotoxes[0].tox, 0, true, nullptr);
do {
iterate_all_wait(2, toxes, state, 200);
} while (!state[1].friend_is_typing);
iterate_all_wait(2, autotoxes, 200);
} while (!((State *)autotoxes[1].state)->friend_is_typing);
ck_assert_msg(tox_friend_get_typing(toxes[1], 0, nullptr) == 1,
ck_assert_msg(tox_friend_get_typing(autotoxes[1].tox, 0, nullptr) == 1,
"tox_friend_get_typing should have returned true, but it didn't");
tox_self_set_typing(toxes[0], 0, false, nullptr);
tox_self_set_typing(autotoxes[0].tox, 0, false, nullptr);
do {
iterate_all_wait(2, toxes, state, 200);
} while (state[1].friend_is_typing);
iterate_all_wait(2, autotoxes, 200);
} while (((State *)autotoxes[1].state)->friend_is_typing);
Tox_Err_Friend_Query err_t;
ck_assert_msg(tox_friend_get_typing(toxes[1], 0, &err_t) == 0,
ck_assert_msg(tox_friend_get_typing(autotoxes[1].tox, 0, &err_t) == 0,
"tox_friend_get_typing should have returned false, but it didn't");
ck_assert_msg(err_t == TOX_ERR_FRIEND_QUERY_OK, "tox_friend_get_typing call did not return correct error");
@ -55,6 +54,10 @@ static void test_typing(Tox **toxes, State *state)
int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
run_auto_test(nullptr, 2, test_typing, false);
Run_Auto_Options options = default_run_auto_options;
options.graph = GRAPH_LINEAR;
run_auto_test(nullptr, 2, test_typing, sizeof(State), &options);
return 0;
}