Coverage Report

Created: 2024-01-26 01:52

/work/auto_tests/auto_test_support.c
Line
Count
Source (jump to first uncovered line)
1
#include <assert.h>  // assert
2
#include <stdlib.h>  // calloc, free
3
4
#include "check_compat.h"
5
#include "../testing/misc_tools.h"
6
#include "../toxcore/Messenger.h"
7
#include "../toxcore/mono_time.h"
8
#include "../toxcore/tox_dispatch.h"
9
#include "../toxcore/tox_events.h"
10
#include "../toxcore/tox_struct.h"
11
12
#include "auto_test_support.h"
13
14
#ifndef ABORT_ON_LOG_ERROR
15
#define ABORT_ON_LOG_ERROR true
16
#endif
17
18
#ifndef USE_IPV6
19
#define USE_IPV6 1
20
#endif
21
22
Run_Auto_Options default_run_auto_options(void)
23
886
{
24
886
    return (Run_Auto_Options) {
25
886
        .graph = GRAPH_COMPLETE,
26
886
        .init_autotox = nullptr,
27
886
        .tcp_port = 33188,
28
886
        .events = true,
29
886
    };
30
886
}
31
32
// List of live bootstrap nodes. These nodes should have TCP server enabled.
33
static const struct BootstrapNodes {
34
    const char   *ip;
35
    uint16_t      port;
36
    const uint8_t key[32];
37
} bootstrap_nodes[] = {
38
    {
39
        "tox.abilinski.com", 33445,
40
        0x10, 0xC0, 0x0E, 0xB2, 0x50, 0xC3, 0x23, 0x3E,
41
        0x34, 0x3E, 0x2A, 0xEB, 0xA0, 0x71, 0x15, 0xA5,
42
        0xC2, 0x89, 0x20, 0xE9, 0xC8, 0xD2, 0x94, 0x92,
43
        0xF6, 0xD0, 0x0B, 0x29, 0x04, 0x9E, 0xDC, 0x7E,
44
    },
45
    {
46
        "tox.initramfs.io", 33445,
47
        0x02, 0x80, 0x7C, 0xF4, 0xF8, 0xBB, 0x8F, 0xB3,
48
        0x90, 0xCC, 0x37, 0x94, 0xBD, 0xF1, 0xE8, 0x44,
49
        0x9E, 0x9A, 0x83, 0x92, 0xC5, 0xD3, 0xF2, 0x20,
50
        0x00, 0x19, 0xDA, 0x9F, 0x1E, 0x81, 0x2E, 0x46,
51
    },
52
    {
53
        "tox.plastiras.org", 33445,
54
        0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F,
55
        0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33,
56
        0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED,
57
        0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25,
58
    },
59
    {
60
        "tox.novg.net", 33445,
61
        0xD5, 0x27, 0xE5, 0x84, 0x7F, 0x83, 0x30, 0xD6,
62
        0x28, 0xDA, 0xB1, 0x81, 0x4F, 0x0A, 0x42, 0x2F,
63
        0x6D, 0xC9, 0xD0, 0xA3, 0x00, 0xE6, 0xC3, 0x57,
64
        0x63, 0x4E, 0xE2, 0xDA, 0x88, 0xC3, 0x54, 0x63,
65
    },
66
    { nullptr, 0, 0 },
67
};
68
69
void bootstrap_tox_live_network(Tox *tox, bool enable_tcp)
70
2
{
71
2
    ck_assert(tox != nullptr);
72
73
10
    for (size_t j = 0; bootstrap_nodes[j].ip != nullptr; ++j) {
74
8
        const char *ip = bootstrap_nodes[j].ip;
75
8
        uint16_t port = bootstrap_nodes[j].port;
76
8
        const uint8_t *key = bootstrap_nodes[j].key;
77
78
8
        Tox_Err_Bootstrap err;
79
8
        tox_bootstrap(tox, ip, port, key, &err);
80
81
8
        if (err != TOX_ERR_BOOTSTRAP_OK) {
82
0
            fprintf(stderr, "Failed to bootstrap node %zu (%s): error %d\n", j, ip, err);
83
0
        }
84
85
8
        if (enable_tcp) {
86
8
            tox_add_tcp_relay(tox, ip, port, key, &err);
87
88
8
            if (err != TOX_ERR_BOOTSTRAP_OK) {
89
0
                fprintf(stderr, "Failed to add TCP relay %zu (%s): error %d\n", j, ip, err);
90
0
            }
91
8
        }
92
8
    }
93
2
}
94
95
bool all_connected(const AutoTox *autotoxes, uint32_t tox_count)
96
16.5k
{
97
16.5k
    if (tox_count) {
98
16.5k
        ck_assert(autotoxes != nullptr);
99
16.5k
    }
100
101
17.4k
    for (uint32_t i = 0; i < tox_count; ++i) {
102
17.0k
        if (tox_self_get_connection_status(autotoxes[i].tox) == TOX_CONNECTION_NONE) {
103
16.2k
            return false;
104
16.2k
        }
105
17.0k
    }
106
107
368
    return true;
108
16.5k
}
109
110
bool all_friends_connected(const AutoTox *autotoxes, uint32_t tox_count)
111
9.79k
{
112
9.79k
    if (tox_count) {
113
9.79k
        ck_assert(autotoxes != nullptr);
114
9.79k
    }
115
116
10.6k
    for (uint32_t i = 0; i < tox_count; ++i) {
117
10.3k
        const size_t friend_count = tox_self_get_friend_list_size(autotoxes[i].tox);
118
119
11.5k
        for (size_t j = 0; j < friend_count; ++j) {
120
10.6k
            if (tox_friend_get_connection_status(autotoxes[i].tox, j, nullptr) == TOX_CONNECTION_NONE) {
121
9.48k
                return false;
122
9.48k
            }
123
10.6k
        }
124
10.3k
    }
125
126
314
    return true;
127
9.79k
}
128
129
void iterate_all_wait(AutoTox *autotoxes, uint32_t tox_count, uint32_t wait)
130
31.8k
{
131
31.8k
    if (tox_count) {
132
31.8k
        ck_assert(autotoxes != nullptr);
133
31.8k
    }
134
135
120k
    for (uint32_t i = 0; i < tox_count; ++i) {
136
88.3k
        if (autotoxes[i].alive) {
137
88.3k
            if (autotoxes[i].events) {
138
79.7k
                Tox_Err_Events_Iterate err;
139
79.7k
                Tox_Events *events = tox_events_iterate(autotoxes[i].tox, true, &err);
140
79.7k
                ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK);
141
79.5k
                tox_dispatch_invoke(autotoxes[i].dispatch, events, autotoxes[i].tox, &autotoxes[i]);
142
79.5k
                tox_events_free(events);
143
79.5k
            } else {
144
8.57k
                tox_iterate(autotoxes[i].tox, &autotoxes[i]);
145
8.57k
            }
146
88.1k
            autotoxes[i].clock += wait;
147
88.1k
        }
148
88.3k
    }
149
150
    /* Also actually sleep a little, to allow for local network processing */
151
31.7k
    c_sleep(5);
152
31.7k
}
153
154
static uint64_t get_state_clock_callback(void *user_data)
155
463k
{
156
463k
    const uint64_t *clock = (const uint64_t *)user_data;
157
463k
    return *clock;
158
463k
}
159
160
void set_mono_time_callback(AutoTox *autotox)
161
1.45k
{
162
1.45k
    ck_assert(autotox != nullptr);
163
164
1.45k
    Mono_Time *mono_time = autotox->tox->mono_time;
165
166
1.45k
    autotox->clock = current_time_monotonic(mono_time);
167
1.45k
    ck_assert_msg(autotox->clock >= 1000,
168
1.45k
                  "clock is too low (not initialised?): %lu", (unsigned long)autotox->clock);
169
1.45k
    mono_time_set_current_time_callback(mono_time, nullptr, nullptr);  // set to default first
170
1.45k
    mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &autotox->clock);
171
1.45k
}
172
173
void save_autotox(AutoTox *autotox)
174
6
{
175
6
    ck_assert(autotox != nullptr);
176
177
6
    fprintf(stderr, "Saving #%u\n", autotox->index);
178
179
6
    free(autotox->save_state);
180
6
    autotox->save_state = nullptr;
181
182
6
    autotox->save_size = tox_get_savedata_size(autotox->tox);
183
6
    ck_assert_msg(autotox->save_size > 0, "save is invalid size %u", (unsigned)autotox->save_size);
184
6
    autotox->save_state = (uint8_t *)malloc(autotox->save_size);
185
6
    ck_assert_msg(autotox->save_state != nullptr, "malloc failed");
186
6
    tox_get_savedata(autotox->tox, autotox->save_state);
187
6
}
188
189
void kill_autotox(AutoTox *autotox)
190
7
{
191
7
    ck_assert(autotox != nullptr);
192
7
    ck_assert(autotox->alive);
193
7
    fprintf(stderr, "Killing #%u\n", autotox->index);
194
7
    autotox->alive = false;
195
7
    tox_dispatch_free(autotox->dispatch);
196
7
    tox_kill(autotox->tox);
197
7
}
198
199
void reload(AutoTox *autotox)
200
7
{
201
7
    ck_assert(autotox != nullptr);
202
203
7
    if (autotox->alive) {
204
0
        kill_autotox(autotox);
205
0
    }
206
207
7
    fprintf(stderr, "Reloading #%u\n", autotox->index);
208
7
    ck_assert(autotox->save_state != nullptr);
209
210
7
    struct Tox_Options *const options = tox_options_new(nullptr);
211
7
    ck_assert(options != nullptr);
212
7
    tox_options_set_ipv6_enabled(options, USE_IPV6);
213
7
    tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
214
7
    tox_options_set_savedata_data(options, autotox->save_state, autotox->save_size);
215
7
    autotox->tox = tox_new_log(options, nullptr, &autotox->index);
216
7
    ck_assert(autotox->tox != nullptr);
217
7
    autotox->dispatch = tox_dispatch_new(nullptr);
218
7
    ck_assert(autotox->dispatch != nullptr);
219
7
    if (autotox->events) {
220
7
        tox_events_init(autotox->tox);
221
7
    }
222
7
    tox_options_free(options);
223
224
7
    set_mono_time_callback(autotox);
225
7
    autotox->alive = true;
226
7
}
227
228
static void initialise_autotox(struct Tox_Options *options, AutoTox *autotox, uint32_t index, uint32_t state_size,
229
                               Run_Auto_Options *autotest_opts)
230
1.86k
{
231
1.86k
    autotox->index = index;
232
1.86k
    autotox->events = autotest_opts->events;
233
234
1.86k
    Tox_Err_New err = TOX_ERR_NEW_OK;
235
236
1.86k
    if (index == 0) {
237
981
        struct Tox_Options *default_opts = tox_options_new(nullptr);
238
981
        ck_assert(default_opts != nullptr);
239
240
980
        tox_options_set_ipv6_enabled(default_opts, USE_IPV6);
241
242
980
        if (options == nullptr) {
243
689
            options = default_opts;
244
689
        }
245
246
980
        if (tox_options_get_udp_enabled(options)) {
247
980
            tox_options_set_tcp_port(options, 0);
248
980
            autotest_opts->tcp_port = 0;
249
980
            autotox->tox = tox_new_log(options, &err, &autotox->index);
250
980
            ck_assert_msg(err == TOX_ERR_NEW_OK, "unexpected tox_new error: %d", err);
251
980
        } else {
252
            // Try a few ports for the TCP relay.
253
0
            for (uint16_t tcp_port = autotest_opts->tcp_port; tcp_port < autotest_opts->tcp_port + 200; ++tcp_port) {
254
0
                tox_options_set_tcp_port(options, tcp_port);
255
0
                autotox->tox = tox_new_log(options, &err, &autotox->index);
256
257
0
                if (autotox->tox != nullptr) {
258
0
                    autotest_opts->tcp_port = tcp_port;
259
0
                    break;
260
0
                }
261
262
0
                ck_assert_msg(err == TOX_ERR_NEW_PORT_ALLOC, "unexpected tox_new error (expected PORT_ALLOC): %d", err);
263
0
            }
264
0
        }
265
266
790
        tox_options_free(default_opts);
267
882
    } else {
268
        // No TCP relay enabled for all the other toxes.
269
882
        if (options != nullptr) {
270
235
            tox_options_set_tcp_port(options, 0);
271
235
        }
272
273
882
        autotox->tox = tox_new_log(options, &err, &autotox->index);
274
882
    }
275
276
1.67k
    ck_assert_msg(autotox->tox != nullptr, "failed to create tox instance #%u (error = %d)", index, err);
277
278
1.44k
    set_mono_time_callback(autotox);
279
280
1.44k
    autotox->dispatch = tox_dispatch_new(nullptr);
281
1.44k
    ck_assert(autotox->dispatch != nullptr);
282
1.43k
    if (autotox->events) {
283
1.41k
        tox_events_init(autotox->tox);
284
1.41k
    }
285
286
1.43k
    autotox->alive = true;
287
1.43k
    autotox->save_state = nullptr;
288
289
1.43k
    if (state_size > 0) {
290
1.33k
        autotox->state = calloc(1, state_size);
291
1.33k
        ck_assert(autotox->state != nullptr);
292
1.32k
        ck_assert_msg(autotox->state != nullptr, "failed to allocate state");
293
1.32k
    } else {
294
99
        autotox->state = nullptr;
295
99
    }
296
297
1.42k
    if (autotest_opts->init_autotox != nullptr) {
298
0
        autotest_opts->init_autotox(autotox, index);
299
0
    }
300
1.42k
}
301
302
static void autotox_add_friend(AutoTox *autotoxes, uint32_t adding, uint32_t added)
303
1.35k
{
304
1.35k
    uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
305
1.35k
    tox_self_get_public_key(autotoxes[added].tox, public_key);
306
1.35k
    Tox_Err_Friend_Add err;
307
1.35k
    tox_friend_add_norequest(autotoxes[adding].tox, public_key, &err);
308
1.35k
    ck_assert(err == TOX_ERR_FRIEND_ADD_OK);
309
1.35k
}
310
311
static void initialise_friend_graph(Graph_Type graph, uint32_t num_toxes, AutoTox *autotoxes)
312
543
{
313
543
    if (graph == GRAPH_LINEAR) {
314
404
        printf("toxes #%d-#%u each add adjacent toxes as friends\n", 0, num_toxes - 1);
315
316
1.28k
        for (uint32_t i = 0; i < num_toxes; ++i) {
317
2.61k
            for (uint32_t j = i - 1; j != i + 3; j += 2) {
318
1.73k
                if (j < num_toxes) {
319
969
                    autotox_add_friend(autotoxes, i, j);
320
969
                }
321
1.73k
            }
322
878
        }
323
404
    } else if (graph == GRAPH_COMPLETE) {
324
139
        printf("toxes #%d-#%u add each other as friends\n", 0, num_toxes - 1);
325
326
430
        for (uint32_t i = 0; i < num_toxes; ++i) {
327
969
            for (uint32_t j = 0; j < num_toxes; ++j) {
328
678
                if (i != j) {
329
387
                    autotox_add_friend(autotoxes, i, j);
330
387
                }
331
678
            }
332
291
        }
333
139
    } else {
334
0
        ck_abort_msg("Unknown graph type");
335
0
    }
336
543
}
337
338
static void bootstrap_autotoxes(const Tox_Options *options, uint32_t tox_count, const Run_Auto_Options *autotest_opts,
339
                                AutoTox *autotoxes)
340
498
{
341
498
    const bool udp_enabled = options != nullptr ? tox_options_get_udp_enabled(options) : true;
342
343
498
    printf("bootstrapping all toxes off tox 0\n");
344
498
    uint8_t dht_key[TOX_PUBLIC_KEY_SIZE];
345
498
    tox_self_get_dht_id(autotoxes[0].tox, dht_key);
346
498
    const uint16_t dht_port = tox_self_get_udp_port(autotoxes[0].tox, nullptr);
347
348
997
    for (uint32_t i = 1; i < tox_count; ++i) {
349
605
        Tox_Err_Bootstrap err;
350
605
        tox_bootstrap(autotoxes[i].tox, "localhost", dht_port, dht_key, &err);
351
605
        ck_assert_msg(err == TOX_ERR_BOOTSTRAP_OK, "bootstrap error for port %d: %d", dht_port, err);
352
605
    }
353
354
392
    if (!udp_enabled) {
355
0
        ck_assert(autotest_opts->tcp_port != 0);
356
0
        printf("bootstrapping all toxes to local TCP relay running on port %d\n", autotest_opts->tcp_port);
357
358
0
        for (uint32_t i = 0; i < tox_count; ++i) {
359
0
            Tox_Err_Bootstrap err;
360
0
            tox_add_tcp_relay(autotoxes[i].tox, "localhost", autotest_opts->tcp_port, dht_key, &err);
361
0
            ck_assert(err == TOX_ERR_BOOTSTRAP_OK);
362
0
        }
363
0
    }
364
392
}
365
366
typedef void autotox_test_cb(AutoTox *autotoxes);
367
368
void run_auto_test(struct Tox_Options *options, uint32_t tox_count, autotox_test_cb *test,
369
                   uint32_t state_size, Run_Auto_Options *autotest_opts)
370
982
{
371
982
    printf("initialising %u toxes\n", tox_count);
372
373
982
    AutoTox *autotoxes = (AutoTox *)calloc(tox_count, sizeof(AutoTox));
374
375
982
    ck_assert(autotoxes != nullptr);
376
377
2.84k
    for (uint32_t i = 0; i < tox_count; ++i) {
378
1.86k
        initialise_autotox(options, &autotoxes[i], i, state_size, autotest_opts);
379
1.86k
    }
380
381
981
    initialise_friend_graph(autotest_opts->graph, tox_count, autotoxes);
382
383
981
    bootstrap_autotoxes(options, tox_count, autotest_opts, autotoxes);
384
385
17.1k
    do {
386
17.1k
        iterate_all_wait(autotoxes, tox_count, ITERATION_INTERVAL);
387
17.1k
    } while (!all_connected(autotoxes, tox_count));
388
389
981
    printf("toxes are online\n");
390
391
10.2k
    do {
392
10.2k
        iterate_all_wait(autotoxes, tox_count, ITERATION_INTERVAL);
393
10.2k
    } while (!all_friends_connected(autotoxes, tox_count));
394
395
981
    printf("tox clients connected\n");
396
397
981
    test(autotoxes);
398
399
1.39k
    for (uint32_t i = 0; i < tox_count; ++i) {
400
413
        tox_dispatch_free(autotoxes[i].dispatch);
401
413
        tox_kill(autotoxes[i].tox);
402
413
        free(autotoxes[i].state);
403
413
        free(autotoxes[i].save_state);
404
413
    }
405
406
981
    free(autotoxes);
407
981
}
408
409
static const char *tox_log_level_name(Tox_Log_Level level)
410
16.3k
{
411
16.3k
    switch (level) {
412
0
        case TOX_LOG_LEVEL_TRACE:
413
0
            return "TRACE";
414
415
7.34k
        case TOX_LOG_LEVEL_DEBUG:
416
7.34k
            return "DEBUG";
417
418
40
        case TOX_LOG_LEVEL_INFO:
419
40
            return "INFO";
420
421
7.99k
        case TOX_LOG_LEVEL_WARNING:
422
7.99k
            return "WARNING";
423
424
962
        case TOX_LOG_LEVEL_ERROR:
425
962
            return "ERROR";
426
16.3k
    }
427
428
0
    return "<unknown>";
429
16.3k
}
430
431
void print_debug_log(Tox *m, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
432
                     const char *message, void *user_data)
433
2.87M
{
434
2.87M
    if (level == TOX_LOG_LEVEL_TRACE) {
435
2.86M
        return;
436
2.86M
    }
437
438
16.3k
    const uint32_t index = user_data ? *(uint32_t *)user_data : 0;
439
16.3k
    fprintf(stderr, "[#%u] %s %s:%u\t%s:\t%s\n", index, tox_log_level_name(level), file, line, func, message);
440
441
16.3k
    if (level == TOX_LOG_LEVEL_ERROR && ABORT_ON_LOG_ERROR) {
442
0
        fputs("Aborting test program\n", stderr);
443
0
        abort();
444
0
    }
445
16.3k
}
446
447
448
void print_debug_logger(void *context, Logger_Level level, const char *file, int line, const char *func, const char *message, void *userdata)
449
122k
{
450
122k
    print_debug_log(nullptr, (Tox_Log_Level) level, file, (uint32_t) line, func, message, userdata);
451
122k
}
452
453
Tox *tox_new_log_lan(struct Tox_Options *options, Tox_Err_New *err, void *log_user_data, bool lan_discovery)
454
2.25k
{
455
2.25k
    struct Tox_Options *log_options = options;
456
457
2.25k
    if (log_options == nullptr) {
458
864
        log_options = tox_options_new(nullptr);
459
864
    }
460
461
2.25k
    assert(log_options != nullptr);
462
463
2.25k
    tox_options_set_ipv6_enabled(log_options, USE_IPV6);
464
2.25k
    tox_options_set_local_discovery_enabled(log_options, lan_discovery);
465
    // Use a higher start port for non-LAN-discovery tests so it's more likely for the LAN discovery
466
    // test to get the default port 33445.
467
2.25k
    const uint16_t start_port = lan_discovery ? 33445 : 33545;
468
2.25k
    tox_options_set_start_port(log_options, start_port);
469
2.25k
    tox_options_set_end_port(log_options, start_port + 2000);
470
2.25k
    tox_options_set_log_callback(log_options, &print_debug_log);
471
2.25k
    tox_options_set_log_user_data(log_options, log_user_data);
472
2.25k
    Tox *tox = tox_new(log_options, err);
473
474
2.25k
    if (options == nullptr) {
475
864
        tox_options_free(log_options);
476
864
    }
477
478
2.25k
    return tox;
479
2.25k
}
480
481
Tox *tox_new_log(struct Tox_Options *options, Tox_Err_New *err, void *log_user_data)
482
2.18k
{
483
2.18k
    return tox_new_log_lan(options, err, log_user_data, false);
484
2.18k
}