/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 |