|
|
|
|
@ -27,6 +27,7 @@
|
|
|
|
|
#include "../lib/debug_config.h" |
|
|
|
|
#include "../lib/mem.h" |
|
|
|
|
#include "test_utils.h" |
|
|
|
|
#include "test_clock.h" |
|
|
|
|
|
|
|
|
|
#include <sqlite3.h> |
|
|
|
|
#define OPENSSL_API_COMPAT 0x10100000L |
|
|
|
|
@ -343,7 +344,8 @@ static void destroy_instances(int n) {
|
|
|
|
|
static int wait_connected(int n) { |
|
|
|
|
if (n <= 1) return 1; |
|
|
|
|
int need = n * (n - 1); |
|
|
|
|
for (int a = 0; a < 2000; a++) { |
|
|
|
|
uint64_t deadline = get_time_tb() + 20000; |
|
|
|
|
while (get_time_tb() < deadline) { |
|
|
|
|
int ok = 0; |
|
|
|
|
for (int i = 0; i < n; i++) { |
|
|
|
|
struct ll_entry* e = g_inst[i]->connections->head; |
|
|
|
|
@ -358,13 +360,15 @@ static int wait_connected(int n) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (ok >= need) return 1; |
|
|
|
|
uasync_poll(g_ua, POLL_MS); |
|
|
|
|
test_clock_poll(g_ua, POLL_MS); |
|
|
|
|
} |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "JOIN test: connection timeout nodes=%d required_links=%d budget_ms=2000", n, need); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int wait_chat_bgp(int n) { |
|
|
|
|
for (int a = 0; a < 8000; a++) { |
|
|
|
|
uint64_t deadline = get_time_tb() + 80000; |
|
|
|
|
while (get_time_tb() < deadline) { |
|
|
|
|
int ok = 1; |
|
|
|
|
for (int i = 0; i < n && ok; i++) { |
|
|
|
|
struct TOPO_GROUP* g = topo_groups_find(g_inst[i]->topo_groups, g_group_id); |
|
|
|
|
@ -376,8 +380,10 @@ static int wait_chat_bgp(int n) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (ok) return 1; |
|
|
|
|
uasync_poll(g_ua, POLL_MS); |
|
|
|
|
test_clock_poll(g_ua, POLL_MS); |
|
|
|
|
} |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "JOIN test: group routes timeout nodes=%d group=%llu budget_ms=8000", |
|
|
|
|
n, (unsigned long long)g_group_id); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -488,23 +494,37 @@ static void t_validate_pubkey(void) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct registration_result { int calls, result; }; |
|
|
|
|
struct registration_result { int calls, result; uint64_t fired_tb; }; |
|
|
|
|
static void registered(void* arg, int result) { |
|
|
|
|
struct registration_result* r = arg; |
|
|
|
|
r->calls++; r->result = result; |
|
|
|
|
r->calls++; r->result = result; r->fired_tb = get_time_tb(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void poll_ms(int ms) { |
|
|
|
|
uint64_t until = get_time_tb() + (uint64_t)ms * 10; |
|
|
|
|
while (get_time_tb() < until) uasync_poll(g_ua, POLL_MS); |
|
|
|
|
test_clock_run_for(g_ua, ms * 10); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int wait_registered(struct registration_result* r) { |
|
|
|
|
uint64_t until = get_time_tb() + JOIN_REGISTER_TIMEOUT_TB + 10000; |
|
|
|
|
while (!r->calls && get_time_tb() < until) uasync_poll(g_ua, POLL_MS); |
|
|
|
|
while (!r->calls && get_time_tb() < until) test_clock_poll(g_ua, POLL_MS); |
|
|
|
|
return r->calls == 1 && r->result == CHAT_JOIN_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Убеждаемся, что регистрация жива до срока; затем настоящий таймер выдаёт ровно один TIMEOUT. */ |
|
|
|
|
static int wait_registration_timeout(struct registration_result* r, uint64_t started) { |
|
|
|
|
uint64_t before = started + JOIN_REGISTER_TIMEOUT_TB - 1000, now = get_time_tb(); |
|
|
|
|
if (now < before) test_clock_run_for(g_ua, (int)(before - now)); |
|
|
|
|
int pending = !r->calls && g_inst[0]->join_registrations != NULL; |
|
|
|
|
wait_registered(r); |
|
|
|
|
int ok = pending && r->calls == 1 && r->result == CHAT_JOIN_TIMEOUT && r->fired_tb + 10 >= started + JOIN_REGISTER_TIMEOUT_TB; |
|
|
|
|
if (!ok) DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "JOIN timeout failed: pending=%d calls=%d result=%d fired_tb=%llu started_tb=%llu budget_tb=%d", |
|
|
|
|
pending, r->calls, r->result, (unsigned long long)r->fired_tb, |
|
|
|
|
(unsigned long long)started, JOIN_REGISTER_TIMEOUT_TB); |
|
|
|
|
else DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "JOIN timeout: pending before deadline; one TIMEOUT elapsed_tb=%llu budget_tb=%d", |
|
|
|
|
(unsigned long long)(r->fired_tb - started), JOIN_REGISTER_TIMEOUT_TB); |
|
|
|
|
return ok; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static etcp_recv_fn original_join_recv; |
|
|
|
|
static struct ll_entry* held_ack; |
|
|
|
|
static struct ETCP_CONN* held_conn; |
|
|
|
|
@ -573,11 +593,12 @@ static void t_registration_edges(void) {
|
|
|
|
|
TEST("registration: missing ACK times out once, late ACK ignored"); { |
|
|
|
|
struct registration_result r = {0}; |
|
|
|
|
uint64_t key = JOIN_KEY + 12; |
|
|
|
|
uint64_t started = get_time_tb(); |
|
|
|
|
struct chat_join_registration* req = chat_join_register_key(g_inst[0], g_group_id, g_nid[1], key, registered, &r); |
|
|
|
|
wait_registered(&r); |
|
|
|
|
int timed_out = wait_registration_timeout(&r, started); |
|
|
|
|
int had_ack = held_ack != NULL; |
|
|
|
|
release_ack(); poll_ms(20); |
|
|
|
|
if (req && had_ack && r.calls == 1 && r.result == CHAT_JOIN_TIMEOUT && !g_inst[0]->join_registrations |
|
|
|
|
if (req && had_ack && timed_out && r.calls == 1 && r.result == CHAT_JOIN_TIMEOUT && !g_inst[0]->join_registrations |
|
|
|
|
&& !chat_join_lookup_inviter(g_inst[0], g_group_id, key)) OK(); else FAIL(); |
|
|
|
|
if (!r.calls && req) chat_join_cancel_registration(req); |
|
|
|
|
} |
|
|
|
|
@ -637,11 +658,12 @@ static void t_registration_edges(void) {
|
|
|
|
|
} |
|
|
|
|
TEST("registration: connection node shutdown times out without success"); { |
|
|
|
|
struct registration_result r = {0}; |
|
|
|
|
uint64_t started = get_time_tb(); |
|
|
|
|
struct chat_join_registration* req = chat_join_register_key(g_inst[0], g_group_id, g_nid[1], JOIN_KEY + 27, registered, &r); |
|
|
|
|
chat_join_destroy(g_inst[1]); member_sync_destroy(g_inst[1]); |
|
|
|
|
g_inst[1]->running = 0; utun_instance_destroy(g_inst[1]); g_inst[1] = NULL; |
|
|
|
|
wait_registered(&r); |
|
|
|
|
if (req && r.calls == 1 && r.result == CHAT_JOIN_TIMEOUT && !g_inst[0]->join_registrations |
|
|
|
|
int timed_out = wait_registration_timeout(&r, started); |
|
|
|
|
if (req && timed_out && r.calls == 1 && r.result == CHAT_JOIN_TIMEOUT && !g_inst[0]->join_registrations |
|
|
|
|
&& !chat_join_lookup_inviter(g_inst[0], g_group_id, JOIN_KEY + 27)) OK(); else FAIL(); |
|
|
|
|
if (!r.calls && req) chat_join_cancel_registration(req); |
|
|
|
|
} |
|
|
|
|
@ -704,6 +726,7 @@ static void t_integration(void) {
|
|
|
|
|
|
|
|
|
|
int main(void) { |
|
|
|
|
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR); |
|
|
|
|
test_clock_init(1000); |
|
|
|
|
if (getenv("UTUN_TEST_DEBUG")) { |
|
|
|
|
debug_set_category_level_by_name("chat_sync", "info"); |
|
|
|
|
debug_set_category_level_by_name("member_sync", "info"); |
|
|
|
|
@ -748,5 +771,6 @@ int main(void) {
|
|
|
|
|
uasync_destroy(g_ua, 0); g_ua = NULL; |
|
|
|
|
} |
|
|
|
|
t_rmdir(g_tdir); |
|
|
|
|
test_clock_finish(); |
|
|
|
|
return G_FAILED > 0 ? 1 : 0; |
|
|
|
|
} |
|
|
|
|
|