tomato-testing/auto_tests/group_invite_test.c
Green Sky 227425b90e Squashed 'external/toxcore/c-toxcore/' content from commit 67badf69
git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: 67badf69416a74e74f6d7eb51dd96f37282b8455
2023-07-25 11:53:09 +02:00

284 lines
9.7 KiB
C

/*
* Tests group invites as well as join restrictions, including password protection, privacy state,
* and peer limits. Ensures sure that the peer being blocked from joining successfully receives
* the invite fail packet with the correct message.
*
* This test also checks that many peers can successfully join the group simultaneously.
*/
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "auto_test_support.h"
#include "check_compat.h"
typedef struct State {
uint32_t num_peers;
bool peer_limit_fail;
bool password_fail;
bool connected;
size_t messages_received;
} State;
#define NUM_GROUP_TOXES 8 // must be > 7
#define PASSWORD "dadada"
#define PASS_LEN (sizeof(PASSWORD) - 1)
#define WRONG_PASS "dadadada"
#define WRONG_PASS_LEN (sizeof(WRONG_PASS) - 1)
static bool group_has_full_graph(const AutoTox *autotoxes, uint32_t group_number, uint32_t expected_peer_count)
{
for (size_t i = 7; i < NUM_GROUP_TOXES; ++i) {
const State *state = (const State *)autotoxes[i].state;
if (state->num_peers < expected_peer_count) {
return false;
}
}
const State *state0 = (const State *)autotoxes[0].state;
const State *state1 = (const State *)autotoxes[1].state;
const State *state5 = (const State *)autotoxes[5].state;
if (state0->num_peers < expected_peer_count || state1->num_peers < expected_peer_count
|| state5->num_peers < expected_peer_count) {
return false;
}
return true;
}
static void group_join_fail_handler(Tox *tox, uint32_t group_number, Tox_Group_Join_Fail fail_type, void *user_data)
{
AutoTox *autotox = (AutoTox *)user_data;
ck_assert(autotox != nullptr);
State *state = (State *)autotox->state;
switch (fail_type) {
case TOX_GROUP_JOIN_FAIL_PEER_LIMIT: {
state->peer_limit_fail = true;
break;
}
case TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD: {
state->password_fail = true;
break;
}
case TOX_GROUP_JOIN_FAIL_UNKNOWN:
// intentional fallthrough
default: {
ck_assert_msg(false, "Got unknown join fail");
return;
}
}
}
static void group_self_join_handler(Tox *tox, uint32_t group_number, void *user_data)
{
AutoTox *autotox = (AutoTox *)user_data;
ck_assert(autotox != nullptr);
State *state = (State *)autotox->state;
state->connected = true;
}
static void group_peer_join_handler(Tox *tox, uint32_t group_number, uint32_t peer_id, void *user_data)
{
AutoTox *autotox = (AutoTox *)user_data;
ck_assert(autotox != nullptr);
State *state = (State *)autotox->state;
++state->num_peers;
ck_assert(state->num_peers < NUM_GROUP_TOXES);
}
static void group_invite_test(AutoTox *autotoxes)
{
#ifndef VANILLA_NACL
ck_assert_msg(NUM_GROUP_TOXES > 7, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES);
for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) {
tox_callback_group_peer_join(autotoxes[i].tox, group_peer_join_handler);
tox_callback_group_join_fail(autotoxes[i].tox, group_join_fail_handler);
tox_callback_group_self_join(autotoxes[i].tox, group_self_join_handler);
}
Tox *tox0 = autotoxes[0].tox;
Tox *tox1 = autotoxes[1].tox;
Tox *tox2 = autotoxes[2].tox;
Tox *tox3 = autotoxes[3].tox;
Tox *tox4 = autotoxes[4].tox;
Tox *tox5 = autotoxes[5].tox;
Tox *tox6 = autotoxes[6].tox;
State *state0 = (State *)autotoxes[0].state;
State *state2 = (State *)autotoxes[2].state;
State *state3 = (State *)autotoxes[3].state;
State *state4 = (State *)autotoxes[4].state;
State *state5 = (State *)autotoxes[5].state;
State *state6 = (State *)autotoxes[6].state;
Tox_Err_Group_New new_err;
uint32_t groupnumber = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)"test", 4,
(const uint8_t *)"test", 4, &new_err);
ck_assert_msg(new_err == TOX_ERR_GROUP_NEW_OK, "tox_group_new failed: %d", new_err);
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
Tox_Err_Group_State_Queries id_err;
uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE];
tox_group_get_chat_id(tox0, groupnumber, chat_id, &id_err);
ck_assert_msg(id_err == TOX_ERR_GROUP_STATE_QUERIES_OK, "%d", id_err);
// peer 1 joins public group with no password
Tox_Err_Group_Join join_err;
tox_group_join(tox1, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
while (state0->num_peers < 1) {
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
}
printf("Peer 1 joined group\n");
// founder sets a password
Tox_Err_Group_Founder_Set_Password pass_set_err;
tox_group_founder_set_password(tox0, groupnumber, (const uint8_t *)PASSWORD, PASS_LEN, &pass_set_err);
ck_assert_msg(pass_set_err == TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK, "%d", pass_set_err);
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000);
// peer 2 attempts to join with no password
tox_group_join(tox2, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
while (!state2->password_fail) {
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
}
printf("Peer 2 successfully blocked with no password\n");
// peer 3 attempts to join with invalid password
tox_group_join(tox3, chat_id, (const uint8_t *)"Test", 4, (const uint8_t *)WRONG_PASS, WRONG_PASS_LEN, &join_err);
ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
while (!state3->password_fail) {
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
}
printf("Peer 3 successfully blocked with invalid password\n");
// founder sets peer limit to 1
Tox_Err_Group_Founder_Set_Peer_Limit limit_set_err;
tox_group_founder_set_peer_limit(tox0, groupnumber, 1, &limit_set_err);
ck_assert_msg(limit_set_err == TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK, "%d", limit_set_err);
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000);
// peer 4 attempts to join with correct password
tox_group_join(tox4, chat_id, (const uint8_t *)"Test", 4, (const uint8_t *)PASSWORD, PASS_LEN, &join_err);
ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
while (!state4->peer_limit_fail) {
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
}
printf("Peer 4 successfully blocked from joining full group\n");
// founder removes password and increases peer limit to 100
tox_group_founder_set_password(tox0, groupnumber, nullptr, 0, &pass_set_err);
ck_assert_msg(pass_set_err == TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK, "%d", pass_set_err);
tox_group_founder_set_peer_limit(tox0, groupnumber, 100, &limit_set_err);
ck_assert_msg(limit_set_err == TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK, "%d", limit_set_err);
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000);
// peer 5 attempts to join group
tox_group_join(tox5, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
while (!state5->connected) {
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
}
printf("Peer 5 successfully joined the group\n");
// founder makes group private
Tox_Err_Group_Founder_Set_Privacy_State priv_err;
tox_group_founder_set_privacy_state(tox0, groupnumber, TOX_GROUP_PRIVACY_STATE_PRIVATE, &priv_err);
ck_assert_msg(priv_err == TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK, "%d", priv_err);
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000);
// peer 6 attempts to join group via chat ID
tox_group_join(tox6, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
// since we don't receive a fail packet in this case we just wait a while and check if we're in the group
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 20000);
ck_assert(!state6->connected);
printf("Peer 6 failed to join private group via chat ID\n");
// founder makes group public again
tox_group_founder_set_privacy_state(tox0, groupnumber, TOX_GROUP_PRIVACY_STATE_PUBLIC, &priv_err);
ck_assert_msg(priv_err == TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK, "%d", priv_err);
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
const uint32_t num_new_peers = NUM_GROUP_TOXES - 7;
printf("Connecting %u peers at the same time\n", num_new_peers);
for (size_t i = 7; i < NUM_GROUP_TOXES; ++i) {
tox_group_join(autotoxes[i].tox, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
}
const uint32_t expected_peer_count = num_new_peers + state0->num_peers + 1;
while (!group_has_full_graph(autotoxes, groupnumber, expected_peer_count)) {
iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
}
printf("Every peer sees every other peer\n");
for (size_t i = 0; i < NUM_GROUP_TOXES; i++) {
Tox_Err_Group_Leave err_exit;
tox_group_leave(autotoxes[i].tox, 0, nullptr, 0, &err_exit);
ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK);
}
printf("All tests passed!\n");
#endif // VANILLA_NACL
}
int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);
Run_Auto_Options autotest_opts = default_run_auto_options();
autotest_opts.graph = GRAPH_COMPLETE;
run_auto_test(nullptr, NUM_GROUP_TOXES, group_invite_test, sizeof(State), &autotest_opts);
return 0;
}
#undef NUM_GROUP_TOXES
#undef PASSWORD
#undef PASS_LEN
#undef WRONG_PASS
#undef WRONG_PASS_LEN