/work/auto_tests/scenarios/scenario_group_moderation_test.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "framework/framework.h" |
2 | | #include <stdio.h> |
3 | | #include <string.h> |
4 | | #include <stdlib.h> |
5 | | |
6 | 188 | #define NUM_PEERS 5 |
7 | 2 | #define GROUP_NAME "Moderation Test Group" |
8 | 1 | #define GROUP_NAME_LEN (sizeof(GROUP_NAME) - 1) |
9 | | |
10 | | typedef struct { |
11 | | uint32_t group_number; |
12 | | uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; |
13 | | bool chat_id_ready; |
14 | | uint32_t peer_count; |
15 | | bool connected; |
16 | | Tox_Group_Role self_role; |
17 | | Tox_Group_Voice_State voice_state; |
18 | | bool kicked; |
19 | | uint32_t peer_ids[NUM_PEERS]; // Map node index to group peer_id |
20 | | Tox_Group_Mod_Event last_mod_event; |
21 | | uint32_t last_mod_target; |
22 | | } ModState; |
23 | | |
24 | | static void on_group_self_join(const Tox_Event_Group_Self_Join *event, void *user_data) |
25 | 13 | { |
26 | 13 | ToxNode *self = (ToxNode *)user_data; |
27 | 13 | ModState *state = (ModState *)tox_node_get_script_ctx(self); |
28 | 13 | state->connected = true; |
29 | 13 | uint32_t group_number = tox_event_group_self_join_get_group_number(event); |
30 | 13 | uint32_t self_id = tox_group_self_get_peer_id(tox_node_get_tox(self), group_number, nullptr); |
31 | 13 | state->self_role = tox_group_self_get_role(tox_node_get_tox(self), group_number, nullptr); |
32 | 13 | tox_node_log(self, "Joined group %u (Peer ID: %u) with role %s", group_number, self_id, tox_group_role_to_string(state->self_role)); |
33 | 13 | } |
34 | | |
35 | | static void on_group_peer_join(const Tox_Event_Group_Peer_Join *event, void *user_data) |
36 | 20 | { |
37 | 20 | ToxNode *self = (ToxNode *)user_data; |
38 | 20 | ModState *state = (ModState *)tox_node_get_script_ctx(self); |
39 | 20 | uint32_t group_number = tox_event_group_peer_join_get_group_number(event); |
40 | 20 | uint32_t peer_id = tox_event_group_peer_join_get_peer_id(event); |
41 | | |
42 | 20 | tox_node_log(self, "Peer %u joined the group", peer_id); |
43 | 20 | state->peer_count++; |
44 | | |
45 | 20 | Tox_Err_Group_Peer_Query q_err; |
46 | 20 | size_t length = tox_group_peer_get_name_size(tox_node_get_tox(self), group_number, peer_id, &q_err); |
47 | 20 | if (q_err == TOX_ERR_GROUP_PEER_QUERY_OK && length > 0) { |
48 | 20 | uint8_t name[TOX_MAX_NAME_LENGTH]; |
49 | 20 | tox_group_peer_get_name(tox_node_get_tox(self), group_number, peer_id, name, &q_err); |
50 | 20 | if (q_err == TOX_ERR_GROUP_PEER_QUERY_OK) { |
51 | 20 | tox_node_log(self, "Peer %u name identified: %.*s", peer_id, (int)length, name); |
52 | 20 | if (length == 7 && memcmp(name, "Founder", 7) == 0) { |
53 | 4 | state->peer_ids[0] = peer_id; |
54 | 16 | } else if (length >= 5 && memcmp(name, "Peer", 4) == 0) { |
55 | 16 | int idx = atoi((const char *)name + 4); |
56 | 16 | if (idx > 0 && idx < NUM_PEERS) { |
57 | 16 | state->peer_ids[idx] = peer_id; |
58 | 16 | } |
59 | 16 | } |
60 | 20 | } |
61 | 20 | } |
62 | 20 | } |
63 | | |
64 | | static void on_group_moderation(const Tox_Event_Group_Moderation *event, void *user_data) |
65 | 45 | { |
66 | 45 | ToxNode *self = (ToxNode *)user_data; |
67 | 45 | ModState *state = (ModState *)tox_node_get_script_ctx(self); |
68 | 45 | state->last_mod_event = tox_event_group_moderation_get_mod_type(event); |
69 | 45 | state->last_mod_target = tox_event_group_moderation_get_target_peer_id(event); |
70 | | |
71 | 45 | Tox_Err_Group_Self_Query err; |
72 | 45 | state->self_role = tox_group_self_get_role(tox_node_get_tox(self), state->group_number, &err); |
73 | | |
74 | 45 | if (state->last_mod_event == TOX_GROUP_MOD_EVENT_KICK && state->last_mod_target == tox_group_self_get_peer_id(tox_node_get_tox(self), state->group_number, nullptr)) { |
75 | 1 | state->kicked = true; |
76 | 1 | } |
77 | | |
78 | 45 | tox_node_log(self, "Moderation event: %s on peer %u. My role is now %s", |
79 | 45 | tox_group_mod_event_to_string(state->last_mod_event), |
80 | 45 | state->last_mod_target, |
81 | 45 | tox_group_role_to_string(state->self_role)); |
82 | 45 | } |
83 | | |
84 | | static void on_group_voice_state(const Tox_Event_Group_Voice_State *event, void *user_data) |
85 | 16 | { |
86 | 16 | ToxNode *self = (ToxNode *)user_data; |
87 | 16 | ModState *state = (ModState *)tox_node_get_script_ctx(self); |
88 | 16 | state->voice_state = tox_event_group_voice_state_get_voice_state(event); |
89 | 16 | tox_node_log(self, "Voice state updated: %u", state->voice_state); |
90 | 16 | } |
91 | | |
92 | | static void common_init(ToxNode *self, ModState *state) |
93 | 8 | { |
94 | 8 | Tox_Dispatch *dispatch = tox_node_get_dispatch(self); |
95 | 8 | tox_events_callback_group_self_join(dispatch, on_group_self_join); |
96 | 8 | tox_events_callback_group_peer_join(dispatch, on_group_peer_join); |
97 | 8 | tox_events_callback_group_moderation(dispatch, on_group_moderation); |
98 | 8 | tox_events_callback_group_voice_state(dispatch, on_group_voice_state); |
99 | | |
100 | 42 | for (int i = 0; i < NUM_PEERS; ++i) { |
101 | 34 | state->peer_ids[i] = UINT32_MAX; |
102 | 34 | } |
103 | | |
104 | 8 | tox_node_log(self, "Waiting for self connection..."); |
105 | 8 | tox_node_wait_for_self_connected(self); |
106 | 8 | tox_node_log(self, "Connected!"); |
107 | 8 | } |
108 | | |
109 | | static void wait_for_peer_role(ToxNode *self, uint32_t peer_idx, Tox_Group_Role expected_role) |
110 | 29 | { |
111 | 29 | ModState *state = (ModState *)tox_node_get_script_ctx(self); |
112 | 29 | tox_node_log(self, "Waiting to see Peer %u with role %s", peer_idx, tox_group_role_to_string(expected_role)); |
113 | | |
114 | 59 | while (tox_scenario_is_running(self)) { |
115 | 59 | uint32_t peer_id = state->peer_ids[peer_idx]; |
116 | | |
117 | 59 | if (peer_id != UINT32_MAX) { |
118 | 59 | Tox_Err_Group_Peer_Query err; |
119 | 59 | Tox_Group_Role role = tox_group_peer_get_role(tox_node_get_tox(self), state->group_number, peer_id, &err); |
120 | | |
121 | 59 | if (err == TOX_ERR_GROUP_PEER_QUERY_OK && role == expected_role) { |
122 | 29 | break; |
123 | 29 | } |
124 | 59 | } |
125 | | |
126 | 30 | tox_scenario_yield(self); |
127 | 30 | } |
128 | | |
129 | 29 | tox_node_log(self, "Peer %u now has role %s", peer_idx, tox_group_role_to_string(expected_role)); |
130 | 29 | } |
131 | | |
132 | | static void founder_script(ToxNode *self, void *ctx) |
133 | 1 | { |
134 | 1 | ModState *state = (ModState *)ctx; |
135 | 1 | Tox *tox = tox_node_get_tox(self); |
136 | 1 | common_init(self, state); |
137 | | |
138 | 1 | Tox_Err_Group_New err_new; |
139 | 1 | state->group_number = tox_group_new(tox, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)GROUP_NAME, GROUP_NAME_LEN, (const uint8_t *)"Founder", 7, &err_new); |
140 | 1 | ck_assert(err_new == TOX_ERR_GROUP_NEW_OK); |
141 | | |
142 | 1 | state->self_role = TOX_GROUP_ROLE_FOUNDER; |
143 | 1 | state->peer_ids[0] = tox_group_self_get_peer_id(tox, state->group_number, nullptr); |
144 | | |
145 | 1 | tox_group_get_chat_id(tox, state->group_number, state->chat_id, nullptr); |
146 | 1 | state->chat_id_ready = true; |
147 | | |
148 | | // Barrier 1: Wait for all peers to join and be seen by everyone |
149 | 1 | WAIT_UNTIL(state->peer_count == NUM_PEERS - 1); |
150 | 1 | tox_node_log(self, "All peers joined"); |
151 | | |
152 | | // Wait until we know all peer IDs |
153 | 5 | for (int i = 1; i < NUM_PEERS; ++i) { |
154 | 4 | WAIT_UNTIL(state->peer_ids[i] != UINT32_MAX); |
155 | 4 | } |
156 | 1 | tox_node_log(self, "All peer IDs identified"); |
157 | | |
158 | 1 | tox_scenario_barrier_wait(self); // Barrier 1: Everyone sees everyone |
159 | | |
160 | | // Barrier 2: Peer 1 becomes Moderator |
161 | 1 | tox_group_set_role(tox, state->group_number, state->peer_ids[1], TOX_GROUP_ROLE_MODERATOR, nullptr); |
162 | 1 | wait_for_peer_role(self, 1, TOX_GROUP_ROLE_MODERATOR); |
163 | 1 | tox_scenario_barrier_wait(self); // Barrier 2: Everyone sees Peer 1 as Moderator |
164 | | |
165 | | // Barrier 3: Peer 2 and 3 become Observer |
166 | 1 | tox_group_set_role(tox, state->group_number, state->peer_ids[2], TOX_GROUP_ROLE_OBSERVER, nullptr); |
167 | 1 | tox_group_set_role(tox, state->group_number, state->peer_ids[3], TOX_GROUP_ROLE_OBSERVER, nullptr); |
168 | 1 | wait_for_peer_role(self, 2, TOX_GROUP_ROLE_OBSERVER); |
169 | 1 | wait_for_peer_role(self, 3, TOX_GROUP_ROLE_OBSERVER); |
170 | 1 | tox_scenario_barrier_wait(self); // Barrier 3: Everyone sees Peer 2/3 as Observers |
171 | | |
172 | | // Barrier 4: Voice State tests |
173 | 1 | tox_node_log(self, "Setting voice state to MODERATOR"); |
174 | 1 | tox_group_set_voice_state(tox, state->group_number, TOX_GROUP_VOICE_STATE_MODERATOR, nullptr); |
175 | 1 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 1 set |
176 | 1 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 1 done |
177 | | |
178 | 1 | tox_node_log(self, "Setting voice state to FOUNDER"); |
179 | 1 | tox_group_set_voice_state(tox, state->group_number, TOX_GROUP_VOICE_STATE_FOUNDER, nullptr); |
180 | 1 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 2 set |
181 | 1 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 2 done |
182 | | |
183 | 1 | tox_node_log(self, "Setting voice state to ALL"); |
184 | 1 | tox_group_set_voice_state(tox, state->group_number, TOX_GROUP_VOICE_STATE_ALL, nullptr); |
185 | 1 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 3 set |
186 | 1 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 3 done |
187 | | |
188 | | // Barrier 5: Peer 1 (Mod) promotes Peer 2 back to User |
189 | 1 | wait_for_peer_role(self, 2, TOX_GROUP_ROLE_USER); |
190 | 1 | tox_scenario_barrier_wait(self); // Barrier 5: Everyone sees Peer 2 as User |
191 | | |
192 | | // Barrier 6: Founder promotes Peer 3 to Moderator |
193 | 1 | tox_group_set_role(tox, state->group_number, state->peer_ids[3], TOX_GROUP_ROLE_MODERATOR, nullptr); |
194 | 1 | wait_for_peer_role(self, 3, TOX_GROUP_ROLE_MODERATOR); |
195 | 1 | tox_scenario_barrier_wait(self); // Barrier 6: Everyone sees Peer 3 as Moderator |
196 | | |
197 | | // Barrier 7: Moderator (Peer 1) attempts to kick/demote Founder (should fail) |
198 | 1 | tox_scenario_barrier_wait(self); // Barrier 7: Founder wait |
199 | | |
200 | | // Barrier 8: Founder kicks Moderator (Peer 1) |
201 | 1 | tox_group_kick_peer(tox, state->group_number, state->peer_ids[1], nullptr); |
202 | 1 | tox_scenario_barrier_wait(self); // Barrier 8: Founder wait |
203 | | |
204 | | // Barrier 9: Founder demotes Moderator (Peer 3) to User |
205 | 1 | tox_group_set_role(tox, state->group_number, state->peer_ids[3], TOX_GROUP_ROLE_USER, nullptr); |
206 | 1 | wait_for_peer_role(self, 3, TOX_GROUP_ROLE_USER); |
207 | 1 | tox_scenario_barrier_wait(self); // Barrier 9: Founder wait |
208 | | |
209 | 1 | tox_scenario_barrier_wait(self); // Done |
210 | 1 | } |
211 | | |
212 | | static void peer_script(ToxNode *self, void *ctx) |
213 | 4 | { |
214 | 4 | ModState *state = (ModState *)ctx; |
215 | 4 | Tox *tox = tox_node_get_tox(self); |
216 | 4 | common_init(self, state); |
217 | | |
218 | 4 | const ToxNode *founder = tox_scenario_get_node(tox_node_get_scenario(self), 0); |
219 | 4 | const ModState *founder_view = (const ModState *)tox_node_get_peer_ctx(founder); |
220 | | |
221 | 5 | while (!founder_view->chat_id_ready) { |
222 | 1 | tox_scenario_yield(self); |
223 | 1 | } |
224 | 4 | tox_node_log(self, "Got chat ID from founder"); |
225 | | |
226 | 4 | char name[16]; |
227 | 4 | snprintf(name, sizeof(name), "Peer%u", tox_node_get_index(self)); |
228 | 4 | Tox_Err_Group_Join err_join; |
229 | 4 | state->group_number = tox_group_join(tox, founder_view->chat_id, (const uint8_t *)name, strlen(name), nullptr, 0, &err_join); |
230 | 4 | if (state->group_number == UINT32_MAX) { |
231 | 0 | tox_node_log(self, "tox_group_join failed with error %u", err_join); |
232 | 0 | } |
233 | 4 | ck_assert(state->group_number != UINT32_MAX); |
234 | | |
235 | 4 | WAIT_UNTIL(state->connected); |
236 | | |
237 | 4 | uint32_t self_id = tox_group_self_get_peer_id(tox, state->group_number, nullptr); |
238 | 4 | state->peer_ids[tox_node_get_index(self)] = self_id; |
239 | | |
240 | | // Barrier 1: Joined |
241 | | // Wait until we know all peer IDs |
242 | 24 | for (uint32_t i = 0; i < NUM_PEERS; ++i) { |
243 | 20 | if (tox_node_get_index(self) != i) { |
244 | 16 | WAIT_UNTIL(state->peer_ids[i] != UINT32_MAX); |
245 | 16 | } |
246 | 20 | } |
247 | 4 | tox_scenario_barrier_wait(self); // Barrier 1: Everyone sees everyone |
248 | | |
249 | | // Barrier 2: Peer 1 Moderator |
250 | 4 | wait_for_peer_role(self, 1, TOX_GROUP_ROLE_MODERATOR); |
251 | 4 | tox_scenario_barrier_wait(self); // Barrier 2: Everyone sees Peer 1 as Moderator |
252 | | |
253 | | // Barrier 3: Peer 2/3 Observer |
254 | 4 | wait_for_peer_role(self, 2, TOX_GROUP_ROLE_OBSERVER); |
255 | 4 | wait_for_peer_role(self, 3, TOX_GROUP_ROLE_OBSERVER); |
256 | 4 | tox_scenario_barrier_wait(self); // Barrier 3: Everyone sees Peer 2/3 as Observers |
257 | | |
258 | | // Barrier 4: Voice State tests |
259 | | // Sub-phase 1: MODERATOR |
260 | 4 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 1 set |
261 | 4 | WAIT_UNTIL(state->voice_state == TOX_GROUP_VOICE_STATE_MODERATOR); |
262 | 4 | Tox_Err_Group_Send_Message err_msg; |
263 | 4 | tox_group_send_message(tox, state->group_number, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)"hello", 5, &err_msg); |
264 | 4 | if (state->self_role == TOX_GROUP_ROLE_MODERATOR || state->self_role == TOX_GROUP_ROLE_FOUNDER) { |
265 | 1 | if (err_msg != TOX_ERR_GROUP_SEND_MESSAGE_OK) { |
266 | 0 | tox_node_log(self, "Expected OK, got %u. Role: %s", err_msg, tox_group_role_to_string(state->self_role)); |
267 | 0 | } |
268 | 1 | ck_assert(err_msg == TOX_ERR_GROUP_SEND_MESSAGE_OK); |
269 | 3 | } else { |
270 | 3 | if (err_msg != TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS) { |
271 | 0 | tox_node_log(self, "Expected PERMISSIONS, got %u. Role: %s", err_msg, tox_group_role_to_string(state->self_role)); |
272 | 0 | } |
273 | 3 | ck_assert(err_msg == TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS); |
274 | 3 | } |
275 | 4 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 1 done |
276 | | |
277 | | // Sub-phase 2: FOUNDER |
278 | 4 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 2 set |
279 | 4 | WAIT_UNTIL(state->voice_state == TOX_GROUP_VOICE_STATE_FOUNDER); |
280 | 4 | tox_group_send_message(tox, state->group_number, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)"hello", 5, &err_msg); |
281 | 4 | if (state->self_role == TOX_GROUP_ROLE_FOUNDER) { |
282 | 0 | ck_assert(err_msg == TOX_ERR_GROUP_SEND_MESSAGE_OK); |
283 | 4 | } else { |
284 | 4 | ck_assert(err_msg == TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS); |
285 | 4 | } |
286 | 4 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 2 done |
287 | | |
288 | | // Sub-phase 3: ALL |
289 | 4 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 3 set |
290 | 4 | WAIT_UNTIL(state->voice_state == TOX_GROUP_VOICE_STATE_ALL); |
291 | 4 | tox_group_send_message(tox, state->group_number, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)"hello", 5, &err_msg); |
292 | 4 | if (state->self_role == TOX_GROUP_ROLE_OBSERVER) { |
293 | 2 | ck_assert(err_msg == TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS); |
294 | 2 | } else { |
295 | 2 | ck_assert(err_msg == TOX_ERR_GROUP_SEND_MESSAGE_OK); |
296 | 2 | } |
297 | 4 | tox_scenario_barrier_wait(self); // Barrier 4 Phase 3 done |
298 | | |
299 | | // Barrier 5: Peer 1 (Mod) promotes Peer 2 back to User |
300 | 4 | if (tox_node_get_index(self) == 1) { // Peer 1 |
301 | 1 | uint32_t peer2_id = state->peer_ids[2]; |
302 | 1 | tox_group_set_role(tox, state->group_number, peer2_id, TOX_GROUP_ROLE_USER, nullptr); |
303 | 1 | } |
304 | 4 | wait_for_peer_role(self, 2, TOX_GROUP_ROLE_USER); |
305 | 4 | tox_scenario_barrier_wait(self); // Barrier 5: Everyone sees Peer 2 as User |
306 | | |
307 | | // Barrier 6: Founder promotes Peer 3 to Moderator |
308 | 4 | wait_for_peer_role(self, 3, TOX_GROUP_ROLE_MODERATOR); |
309 | 4 | tox_scenario_barrier_wait(self); // Barrier 6: Everyone sees Peer 3 as Moderator |
310 | | |
311 | | // Barrier 7: Moderator (Peer 1) attempts to kick/demote Founder (should fail) |
312 | 4 | if (tox_node_get_index(self) == 1) { |
313 | 1 | Tox_Err_Group_Kick_Peer err_kick; |
314 | 1 | uint32_t founder_peer_id = state->peer_ids[0]; |
315 | 1 | tox_group_kick_peer(tox, state->group_number, founder_peer_id, &err_kick); |
316 | 1 | ck_assert(err_kick != TOX_ERR_GROUP_KICK_PEER_OK); |
317 | | |
318 | 1 | Tox_Err_Group_Set_Role err_role; |
319 | 1 | tox_group_set_role(tox, state->group_number, founder_peer_id, TOX_GROUP_ROLE_USER, &err_role); |
320 | 1 | ck_assert(err_role != TOX_ERR_GROUP_SET_ROLE_OK); |
321 | 1 | } |
322 | 4 | tox_scenario_barrier_wait(self); // Barrier 7: Everyone wait |
323 | | |
324 | | // Barrier 8: Founder kicks Moderator (Peer 1) |
325 | 4 | if (tox_node_get_index(self) == 1) { |
326 | 1 | WAIT_UNTIL(state->kicked); |
327 | 1 | tox_scenario_barrier_wait(self); // Barrier 8: Peer 1 reached (it's kicked) |
328 | 1 | return; // Exit script |
329 | 1 | } |
330 | 3 | tox_scenario_barrier_wait(self); // Barrier 8: Everyone else reached |
331 | | |
332 | | // Barrier 9: Founder demotes Moderator (Peer 3) to User |
333 | 3 | wait_for_peer_role(self, 3, TOX_GROUP_ROLE_USER); |
334 | 3 | tox_scenario_barrier_wait(self); // Barrier 9: Everyone sees Peer 3 as User |
335 | | |
336 | 3 | tox_scenario_barrier_wait(self); // Done |
337 | 3 | } |
338 | | |
339 | | int main(int argc, char *argv[]) |
340 | 3 | { |
341 | 3 | setvbuf(stdout, nullptr, _IONBF, 0); |
342 | 3 | setvbuf(stderr, nullptr, _IONBF, 0); |
343 | | |
344 | 3 | ToxScenario *s = tox_scenario_new(argc, argv, 300000); // 5 virtual minutes |
345 | 3 | ModState states[NUM_PEERS] = {0}; |
346 | 3 | ToxNode *nodes[NUM_PEERS]; |
347 | | |
348 | 3 | nodes[0] = tox_scenario_add_node(s, "Founder", founder_script, &states[0], sizeof(ModState)); |
349 | 3 | static char aliases[NUM_PEERS][16]; |
350 | 13 | for (int i = 1; i < NUM_PEERS; ++i) { |
351 | 10 | snprintf(aliases[i], sizeof(aliases[i]), "Peer%d", i); |
352 | 10 | nodes[i] = tox_scenario_add_node(s, aliases[i], peer_script, &states[i], sizeof(ModState)); |
353 | 10 | } |
354 | | |
355 | 16 | for (int i = 0; i < NUM_PEERS; ++i) { |
356 | 72 | for (int j = 0; j < NUM_PEERS; ++j) { |
357 | 59 | if (i != j) { |
358 | 46 | tox_node_bootstrap(nodes[i], nodes[j]); |
359 | 46 | tox_node_friend_add(nodes[i], nodes[j]); |
360 | 46 | } |
361 | 59 | } |
362 | 13 | } |
363 | | |
364 | 3 | ToxScenarioStatus res = tox_scenario_run(s); |
365 | 3 | if (res != TOX_SCENARIO_DONE) { |
366 | 0 | tox_scenario_log(s, "Test failed with status %u", res); |
367 | 0 | return 1; |
368 | 0 | } |
369 | | |
370 | 3 | tox_scenario_free(s); |
371 | 3 | return 0; |
372 | 3 | } |
373 | | |
374 | | #undef GROUP_NAME |
375 | | #undef GROUP_NAME_LEN |
376 | | #undef NUM_PEERS |