Coverage Report

Created: 2025-10-08 19:34

/work/auto_tests/group_tcp_test.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Does a basic functionality test for TCP connections.
3
 */
4
5
#include <stdbool.h>
6
#include <stdint.h>
7
#include <string.h>
8
9
#include "auto_test_support.h"
10
11
0
#define NUM_GROUP_TOXES 2
12
0
#define CODEWORD "RONALD MCDONALD"
13
0
#define CODEWORD_LEN (sizeof(CODEWORD) - 1)
14
15
typedef struct State {
16
    size_t   num_peers;
17
    bool     got_code;
18
    bool     got_second_code;
19
    uint32_t peer_id[NUM_GROUP_TOXES - 1];
20
} State;
21
22
static void group_invite_handler(const Tox_Event_Group_Invite *event, void *user_data)
23
97
{
24
97
    AutoTox *autotox = (AutoTox *)user_data;
25
97
    ck_assert(autotox != nullptr);
26
27
97
    const uint32_t friend_number = tox_event_group_invite_get_friend_number(event);
28
97
    const uint8_t *invite_data = tox_event_group_invite_get_invite_data(event);
29
97
    const size_t length = tox_event_group_invite_get_invite_data_length(event);
30
31
97
    printf("Accepting friend invite\n");
32
33
97
    Tox_Err_Group_Invite_Accept err_accept;
34
97
    tox_group_invite_accept(autotox->tox, friend_number, invite_data, length, (const uint8_t *)"test", 4,
35
97
                            nullptr, 0, &err_accept);
36
97
    ck_assert(err_accept == TOX_ERR_GROUP_INVITE_ACCEPT_OK);
37
97
}
38
39
static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data)
40
40
{
41
40
    AutoTox *autotox = (AutoTox *)user_data;
42
40
    ck_assert(autotox != nullptr);
43
44
40
    State *state = (State *)autotox->state;
45
46
40
    const uint32_t peer_id = tox_event_group_peer_join_get_peer_id(event);
47
48
40
    fprintf(stderr, "joined: %zu, %u\n", state->num_peers, peer_id);
49
40
    ck_assert_msg(state->num_peers < NUM_GROUP_TOXES - 1, "%zu", state->num_peers);
50
51
40
    state->peer_id[state->num_peers++] = peer_id;
52
40
}
53
54
static void group_private_message_handler(const Tox_Event_Group_Private_Message *event, void *user_data)
55
0
{
56
0
    const uint8_t *message = tox_event_group_private_message_get_message(event);
57
0
    const size_t length = tox_event_group_private_message_get_message_length(event);
58
59
0
    AutoTox *autotox = (AutoTox *)user_data;
60
0
    ck_assert(autotox != nullptr);
61
62
0
    State *state = (State *)autotox->state;
63
64
0
    ck_assert(length == CODEWORD_LEN);
65
0
    ck_assert(memcmp(CODEWORD, message, length) == 0);
66
67
0
    printf("Codeword: %s\n", CODEWORD);
68
69
0
    state->got_code = true;
70
0
}
71
72
static void group_message_handler(const Tox_Event_Group_Message *event, void *user_data)
73
0
{
74
0
    const uint8_t *message = tox_event_group_message_get_message(event);
75
0
    const size_t length = tox_event_group_message_get_message_length(event);
76
77
0
    AutoTox *autotox = (AutoTox *)user_data;
78
0
    ck_assert(autotox != nullptr);
79
80
0
    State *state = (State *)autotox->state;
81
82
0
    ck_assert(length == CODEWORD_LEN);
83
0
    ck_assert(memcmp(CODEWORD, message, length) == 0);
84
85
0
    printf("Codeword: %s\n", CODEWORD);
86
87
0
    state->got_second_code = true;
88
0
}
89
90
/*
91
 * We need different constants to make TCP run smoothly. TODO(Jfreegman): is this because of the group
92
 * implementation or just an autotest quirk?
93
 */
94
0
#define GROUP_ITERATION_INTERVAL 100
95
static void iterate_group(AutoTox *autotoxes, uint32_t num_toxes, size_t interval)
96
0
{
97
0
    for (uint32_t i = 0; i < num_toxes; i++) {
98
0
        if (autotoxes[i].alive) {
99
0
            tox_iterate(autotoxes[i].tox, &autotoxes[i]);
100
0
            autotoxes[i].clock += interval;
101
0
        }
102
0
    }
103
104
0
    c_sleep(50);
105
0
}
106
107
static bool all_peers_connected(AutoTox *autotoxes)
108
0
{
109
0
    iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL);
110
111
0
    size_t count = 0;
112
113
0
    for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) {
114
0
        const State *state = (const State *)autotoxes[i].state;
115
116
0
        if (state->num_peers == NUM_GROUP_TOXES - 1) {
117
0
            ++count;
118
0
        }
119
0
    }
120
121
0
    return count == NUM_GROUP_TOXES;
122
0
}
123
124
static bool all_peers_got_code(AutoTox *autotoxes)
125
0
{
126
0
    iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL);
127
128
0
    size_t count = 0;
129
130
0
    for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) {
131
0
        const State *state = (const State *)autotoxes[i].state;
132
133
0
        if (state->got_code) {
134
0
            ++count;
135
0
        }
136
0
    }
137
138
0
    return count == NUM_GROUP_TOXES - 1;
139
0
}
140
141
static void group_tcp_test(AutoTox *autotoxes)
142
0
{
143
0
    ck_assert(NUM_GROUP_TOXES >= 2);
144
145
0
    State *state0 = (State *)autotoxes[0].state;
146
0
    State *state1 = (State *)autotoxes[1].state;
147
148
0
    for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) {
149
0
        tox_events_callback_group_peer_join(autotoxes[i].dispatch, group_peer_join_handler);
150
0
        tox_events_callback_group_private_message(autotoxes[i].dispatch, group_private_message_handler);
151
0
    }
152
153
0
    tox_events_callback_group_message(autotoxes[1].dispatch, group_message_handler);
154
0
    tox_events_callback_group_invite(autotoxes[1].dispatch, group_invite_handler);
155
156
0
    Tox_Err_Group_New new_err;
157
0
    uint32_t groupnumber = tox_group_new(autotoxes[0].tox, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)"test", 4,
158
0
                                         (const uint8_t *)"test", 4, &new_err);
159
0
    ck_assert_msg(new_err == TOX_ERR_GROUP_NEW_OK, "tox_group_new failed: %u", new_err);
160
161
0
    iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL);
162
163
0
    Tox_Err_Group_State_Query id_err;
164
0
    uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE];
165
166
0
    tox_group_get_chat_id(autotoxes[0].tox, groupnumber, chat_id, &id_err);
167
0
    ck_assert_msg(id_err == TOX_ERR_GROUP_STATE_QUERY_OK, "%u", id_err);
168
169
0
    printf("Tox 0 created new group...\n");
170
171
0
    for (size_t i = 1; i < NUM_GROUP_TOXES; ++i) {
172
0
        Tox_Err_Group_Join jerr;
173
0
        tox_group_join(autotoxes[i].tox, chat_id, (const uint8_t *)"test", 4, nullptr, 0, &jerr);
174
0
        ck_assert_msg(jerr == TOX_ERR_GROUP_JOIN_OK, "%u", jerr);
175
0
        iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL * 10);
176
0
    }
177
178
0
    while (!all_peers_connected(autotoxes))
179
0
        ;
180
181
0
    printf("%d peers successfully joined. Waiting for code...\n", NUM_GROUP_TOXES);
182
0
    printf("Tox 0 sending secret code to all peers\n");
183
184
0
    for (size_t i = 0; i < NUM_GROUP_TOXES - 1; ++i) {
185
186
0
        Tox_Err_Group_Send_Private_Message perr;
187
0
        tox_group_send_private_message(autotoxes[0].tox, groupnumber, state0->peer_id[i],
188
0
                                       TOX_MESSAGE_TYPE_NORMAL,
189
0
                                       (const uint8_t *)CODEWORD, CODEWORD_LEN, &perr);
190
0
        ck_assert_msg(perr == TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_OK, "%u", perr);
191
0
    }
192
193
0
    while (!all_peers_got_code(autotoxes))
194
0
        ;
195
196
0
    Tox_Err_Group_Leave err_exit;
197
0
    tox_group_leave(autotoxes[1].tox, groupnumber, nullptr, 0, &err_exit);
198
0
    ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK);
199
200
0
    iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL);
201
202
0
    state0->num_peers = 0;
203
0
    state1->num_peers = 0;
204
205
    // now do a friend invite to make sure the TCP-specific logic for friend invites is okay
206
207
0
    printf("Tox1 leaves group and Tox0 does a friend group invite for tox1\n");
208
209
0
    Tox_Err_Group_Invite_Friend err_invite;
210
0
    tox_group_invite_friend(autotoxes[0].tox, groupnumber, 0, &err_invite);
211
0
    ck_assert(err_invite == TOX_ERR_GROUP_INVITE_FRIEND_OK);
212
213
0
    while (state0->num_peers == 0 && state1->num_peers == 0) {
214
0
        iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL);
215
0
    }
216
217
0
    printf("Tox 1 successfully joined. Waiting for code...\n");
218
219
0
    Tox_Err_Group_Send_Message merr;
220
0
    tox_group_send_message(autotoxes[0].tox, groupnumber, TOX_MESSAGE_TYPE_NORMAL,
221
0
                           (const uint8_t *)CODEWORD, CODEWORD_LEN, &merr);
222
0
    ck_assert(merr == TOX_ERR_GROUP_SEND_MESSAGE_OK);
223
224
0
    while (!state1->got_second_code) {
225
0
        iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL);
226
0
    }
227
228
0
    for (size_t i = 0; i < NUM_GROUP_TOXES; i++) {
229
0
        tox_group_leave(autotoxes[i].tox, groupnumber, nullptr, 0, &err_exit);
230
0
        ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK);
231
0
    }
232
233
0
    printf("Test passed!\n");
234
0
}
235
236
int main(int argc, char **argv)
237
3
{
238
3
    setvbuf(stdout, nullptr, _IONBF, 0);
239
240
3
    struct Tox_Options *options = tox_options_new(nullptr);
241
3
    ck_assert(options != nullptr);
242
243
3
    tox_options_set_udp_enabled(options, false);
244
245
3
    Run_Auto_Options autotest_opts = default_run_auto_options();
246
3
    autotest_opts.graph = GRAPH_COMPLETE;
247
248
    // TODO(JFreegman): Fix this test and remove the "if".
249
3
    if (argc > 2) {
250
0
        run_auto_test(options, NUM_GROUP_TOXES, group_tcp_test, sizeof(State), &autotest_opts);
251
0
    }
252
253
3
    tox_options_free(options);
254
3
    return 0;
255
3
}
256
257
#undef CODEWORD_LEN
258
#undef CODEWORD
259
#undef NUM_GROUP_TOXES