Coverage Report

Created: 2024-01-26 01:52

/work/auto_tests/group_invite_test.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Tests group invites as well as join restrictions, including password protection, privacy state,
3
 * and peer limits. Ensures sure that the peer being blocked from joining successfully receives
4
 * the invite fail packet with the correct message.
5
 *
6
 * This test also checks that many peers can successfully join the group simultaneously.
7
 */
8
9
#include <string.h>
10
#include <stdio.h>
11
#include <stdint.h>
12
13
#include "auto_test_support.h"
14
#include "check_compat.h"
15
16
typedef struct State {
17
    uint32_t num_peers;
18
    bool peer_limit_fail;
19
    bool password_fail;
20
    bool connected;
21
    size_t messages_received;
22
} State;
23
24
1.00k
#define NUM_GROUP_TOXES 8  // must be > 7
25
26
4
#define PASSWORD "dadada"
27
2
#define PASS_LEN (sizeof(PASSWORD) - 1)
28
29
2
#define WRONG_PASS "dadadada"
30
1
#define WRONG_PASS_LEN (sizeof(WRONG_PASS) - 1)
31
32
static bool group_has_full_graph(const AutoTox *autotoxes, uint32_t group_number, uint32_t expected_peer_count)
33
110
{
34
111
    for (size_t i = 7; i < NUM_GROUP_TOXES; ++i) {
35
110
        const State *state = (const State *)autotoxes[i].state;
36
37
110
        if (state->num_peers < expected_peer_count) {
38
109
            return false;
39
109
        }
40
110
    }
41
42
1
    const State *state0 = (const State *)autotoxes[0].state;
43
1
    const State *state1 = (const State *)autotoxes[1].state;
44
1
    const State *state5 = (const State *)autotoxes[5].state;
45
46
1
    if (state0->num_peers < expected_peer_count || state1->num_peers < expected_peer_count
47
1
            || state5->num_peers < expected_peer_count) {
48
0
        return false;
49
0
    }
50
51
1
    return true;
52
1
}
53
54
static void group_join_fail_handler(Tox *tox, const Tox_Event_Group_Join_Fail *event, void *user_data)
55
3
{
56
3
    AutoTox *autotox = (AutoTox *)user_data;
57
3
    ck_assert(autotox != nullptr);
58
59
3
    State *state = (State *)autotox->state;
60
61
3
    const Tox_Group_Join_Fail fail_type = tox_event_group_join_fail_get_fail_type(event);
62
63
3
    switch (fail_type) {
64
1
        case TOX_GROUP_JOIN_FAIL_PEER_LIMIT: {
65
1
            state->peer_limit_fail = true;
66
1
            break;
67
0
        }
68
69
2
        case TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD: {
70
2
            state->password_fail = true;
71
2
            break;
72
0
        }
73
74
0
        case TOX_GROUP_JOIN_FAIL_UNKNOWN:
75
76
        // intentional fallthrough
77
0
        default: {
78
0
            ck_assert_msg(false, "Got unknown join fail");
79
0
            return;
80
0
        }
81
3
    }
82
3
}
83
84
static void group_self_join_handler(Tox *tox, const Tox_Event_Group_Self_Join *event, void *user_data)
85
4
{
86
4
    AutoTox *autotox = (AutoTox *)user_data;
87
4
    ck_assert(autotox != nullptr);
88
89
4
    State *state = (State *)autotox->state;
90
91
4
    state->connected = true;
92
4
}
93
94
static void group_peer_join_handler(Tox *tox, const Tox_Event_Group_Peer_Join *event, void *user_data)
95
40
{
96
40
    AutoTox *autotox = (AutoTox *)user_data;
97
40
    ck_assert(autotox != nullptr);
98
99
40
    State *state = (State *)autotox->state;
100
101
40
    ++state->num_peers;
102
40
    ck_assert(state->num_peers < NUM_GROUP_TOXES);
103
40
}
104
105
static void group_invite_test(AutoTox *autotoxes)
106
1
{
107
1
    ck_assert_msg(NUM_GROUP_TOXES > 7, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES);
108
109
9
    for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) {
110
8
        tox_events_callback_group_peer_join(autotoxes[i].dispatch, group_peer_join_handler);
111
8
        tox_events_callback_group_join_fail(autotoxes[i].dispatch, group_join_fail_handler);
112
8
        tox_events_callback_group_self_join(autotoxes[i].dispatch, group_self_join_handler);
113
8
    }
114
115
1
    Tox *tox0 = autotoxes[0].tox;
116
1
    Tox *tox1 = autotoxes[1].tox;
117
1
    Tox *tox2 = autotoxes[2].tox;
118
1
    Tox *tox3 = autotoxes[3].tox;
119
1
    Tox *tox4 = autotoxes[4].tox;
120
1
    Tox *tox5 = autotoxes[5].tox;
121
1
    Tox *tox6 = autotoxes[6].tox;
122
123
1
    const State *state0 = (const State *)autotoxes[0].state;
124
1
    const State *state2 = (const State *)autotoxes[2].state;
125
1
    const State *state3 = (const State *)autotoxes[3].state;
126
1
    const State *state4 = (const State *)autotoxes[4].state;
127
1
    const State *state5 = (const State *)autotoxes[5].state;
128
1
    const State *state6 = (const State *)autotoxes[6].state;
129
130
1
    Tox_Err_Group_New new_err;
131
1
    uint32_t groupnumber = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)"test", 4,
132
1
                                         (const uint8_t *)"test", 4, &new_err);
133
1
    ck_assert_msg(new_err == TOX_ERR_GROUP_NEW_OK, "tox_group_new failed: %d", new_err);
134
135
1
    iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
136
137
1
    Tox_Err_Group_State_Queries id_err;
138
1
    uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE];
139
140
1
    tox_group_get_chat_id(tox0, groupnumber, chat_id, &id_err);
141
1
    ck_assert_msg(id_err == TOX_ERR_GROUP_STATE_QUERIES_OK, "%d", id_err);
142
143
    // peer 1 joins public group with no password
144
1
    Tox_Err_Group_Join join_err;
145
1
    tox_group_join(tox1, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
146
1
    ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
147
148
10
    while (state0->num_peers < 1) {
149
9
        iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
150
9
    }
151
152
1
    printf("Peer 1 joined group\n");
153
154
    // founder sets a password
155
1
    Tox_Err_Group_Founder_Set_Password pass_set_err;
156
1
    tox_group_founder_set_password(tox0, groupnumber, (const uint8_t *)PASSWORD, PASS_LEN, &pass_set_err);
157
1
    ck_assert_msg(pass_set_err == TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK, "%d", pass_set_err);
158
159
1
    iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000);
160
161
    // peer 2 attempts to join with no password
162
1
    tox_group_join(tox2, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
163
1
    ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
164
165
8
    while (!state2->password_fail) {
166
7
        iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
167
7
    }
168
169
1
    printf("Peer 2 successfully blocked with no password\n");
170
171
    // peer 3 attempts to join with invalid password
172
1
    tox_group_join(tox3, chat_id, (const uint8_t *)"Test", 4, (const uint8_t *)WRONG_PASS, WRONG_PASS_LEN, &join_err);
173
1
    ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
174
175
9
    while (!state3->password_fail) {
176
8
        iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
177
8
    }
178
179
1
    printf("Peer 3 successfully blocked with invalid password\n");
180
181
    // founder sets peer limit to 1
182
1
    Tox_Err_Group_Founder_Set_Peer_Limit limit_set_err;
183
1
    tox_group_founder_set_peer_limit(tox0, groupnumber, 1, &limit_set_err);
184
1
    ck_assert_msg(limit_set_err == TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK, "%d", limit_set_err);
185
186
1
    iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000);
187
188
    // peer 4 attempts to join with correct password
189
1
    tox_group_join(tox4, chat_id, (const uint8_t *)"Test", 4, (const uint8_t *)PASSWORD, PASS_LEN, &join_err);
190
1
    ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
191
192
8
    while (!state4->peer_limit_fail) {
193
7
        iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
194
7
    }
195
196
1
    printf("Peer 4 successfully blocked from joining full group\n");
197
198
    // founder removes password and increases peer limit to 100
199
1
    tox_group_founder_set_password(tox0, groupnumber, nullptr, 0, &pass_set_err);
200
1
    ck_assert_msg(pass_set_err == TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK, "%d", pass_set_err);
201
202
1
    tox_group_founder_set_peer_limit(tox0, groupnumber, 100, &limit_set_err);
203
1
    ck_assert_msg(limit_set_err == TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK, "%d", limit_set_err);
204
205
1
    iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000);
206
207
    // peer 5 attempts to join group
208
1
    tox_group_join(tox5, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
209
1
    ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
210
211
10
    while (!state5->connected) {
212
9
        iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
213
9
    }
214
215
1
    printf("Peer 5 successfully joined the group\n");
216
217
    // founder makes group private
218
1
    Tox_Err_Group_Founder_Set_Privacy_State priv_err;
219
1
    tox_group_founder_set_privacy_state(tox0, groupnumber, TOX_GROUP_PRIVACY_STATE_PRIVATE, &priv_err);
220
1
    ck_assert_msg(priv_err == TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK, "%d", priv_err);
221
222
1
    iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000);
223
224
    // peer 6 attempts to join group via chat ID
225
1
    tox_group_join(tox6, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
226
1
    ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
227
228
    // since we don't receive a fail packet in this case we just wait a while and check if we're in the group
229
1
    iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 20000);
230
231
1
    ck_assert(!state6->connected);
232
233
1
    printf("Peer 6 failed to join private group via chat ID\n");
234
235
    // founder makes group public again
236
1
    tox_group_founder_set_privacy_state(tox0, groupnumber, TOX_GROUP_PRIVACY_STATE_PUBLIC, &priv_err);
237
1
    ck_assert_msg(priv_err == TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK, "%d", priv_err);
238
239
1
    iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
240
241
1
    const uint32_t num_new_peers = NUM_GROUP_TOXES - 7;
242
1
    printf("Connecting %u peers at the same time\n", num_new_peers);
243
244
2
    for (size_t i = 7; i < NUM_GROUP_TOXES; ++i) {
245
1
        tox_group_join(autotoxes[i].tox, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err);
246
1
        ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err);
247
1
    }
248
249
1
    const uint32_t expected_peer_count = num_new_peers + state0->num_peers + 1;
250
251
110
    while (!group_has_full_graph(autotoxes, groupnumber, expected_peer_count)) {
252
109
        iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL);
253
109
    }
254
255
1
    printf("Every peer sees every other peer\n");
256
257
9
    for (size_t i = 0; i < NUM_GROUP_TOXES; i++) {
258
8
        Tox_Err_Group_Leave err_exit;
259
8
        tox_group_leave(autotoxes[i].tox, 0, nullptr, 0, &err_exit);
260
8
        ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK);
261
8
    }
262
263
1
    printf("All tests passed!\n");
264
1
}
265
266
int main(void)
267
721
{
268
721
    setvbuf(stdout, nullptr, _IONBF, 0);
269
270
721
    Run_Auto_Options autotest_opts = default_run_auto_options();
271
721
    autotest_opts.graph = GRAPH_COMPLETE;
272
273
721
    run_auto_test(nullptr, NUM_GROUP_TOXES, group_invite_test, sizeof(State), &autotest_opts);
274
275
721
    return 0;
276
721
}
277
278
#undef NUM_GROUP_TOXES
279
#undef PASSWORD
280
#undef PASS_LEN
281
#undef WRONG_PASS
282
#undef WRONG_PASS_LEN