Browse Source

tests: accelerate standby phases and group connection retries

master
evgeny 2 days ago
parent
commit
d9c8e006b5
  1. 27
      tests/Makefile.am
  2. 19
      tests/test_clock.c
  3. 2
      tests/test_clock.h
  4. 12
      tests/test_group_connect.c
  5. 13
      tests/test_standby_transport.c
  6. 21
      tools/chatgui-android/libutun_lite/tests/test_standby.c

27
tests/Makefile.am

@ -80,7 +80,9 @@ if OS_LINUX
check_PROGRAMS += \
test_reality_fallback \
test_etcp_padding \
test_ll_queue_regressions
test_ll_queue_regressions \
test_standby \
test_standby_transport
endif
# Короткие интеграционные проверки (до 1с).
@ -116,6 +118,7 @@ check_PROGRAMS += \
test_etcp_router_tcp \
test_etcp_connect \
test_call \
test_group_connect \
test_etcp_router \
test_dm_worker \
test_chat_join \
@ -130,6 +133,7 @@ check_PROGRAMS += \
test_stcp_reality_rotation \
test_android_udp_log \
test_pool_corruption_log \
test_group_connect_standby \
test_android_replies
endif
@ -148,17 +152,10 @@ check_PROGRAMS += \
test_chat_join_e2e \
test_media_delivery_chat \
test_member_files_network \
test_group_connect \
test_etcp_reconnect \
test_conn_mgr_phases \
test_socks_http_proxy
if OS_LINUX
check_PROGRAMS += \
test_standby_transport \
test_group_connect_standby
endif
# Длительные проверки и нагрузка.
check_PROGRAMS += \
test_proxy_regressions \
@ -168,7 +165,6 @@ check_PROGRAMS += \
if OS_LINUX
check_PROGRAMS += \
test_standby \
test_uasync_load \
test_auto_socket_dynamic
endif
@ -221,16 +217,18 @@ if OS_LINUX
test_stcp_LDFLAGS = -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=random_bytes -Wl,--wrap=u_malloc_impl -Wl,--wrap=u_calloc_impl
standby_test_sources = ../tools/chatgui-android/libutun_lite/standby.c ../src/utun_instance.c ../src/transport_layer/etcp_keepalive.c
standby_test_cppflags = $(AM_CPPFLAGS) -I$(top_srcdir)/src/chat -I$(top_srcdir)/tools/chatgui-android/libutun_lite -DUTUN_HAVE_STANDBY
test_standby_SOURCES = ../tools/chatgui-android/libutun_lite/tests/test_standby.c $(standby_test_sources)
test_standby_SOURCES = ../tools/chatgui-android/libutun_lite/tests/test_standby.c $(standby_test_sources) $(test_clock_sources)
test_standby_CPPFLAGS = $(standby_test_cppflags)
test_standby_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_standby_transport_SOURCES = test_standby_transport.c $(standby_test_sources)
test_standby_LDFLAGS = $(test_clock_ldflags)
test_standby_transport_SOURCES = test_standby_transport.c $(standby_test_sources) $(test_clock_sources)
test_standby_transport_CPPFLAGS = $(standby_test_cppflags)
test_standby_transport_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_standby_transport_LDFLAGS = -Wl,--wrap=etcp_encrypt_send -Wl,--wrap=uasync_set_timeout
test_group_connect_standby_SOURCES = test_group_connect.c ../src/routing_layer/topo_group_connect.c $(standby_test_sources)
test_standby_transport_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=etcp_encrypt_send -Wl,--wrap=uasync_set_timeout
test_group_connect_standby_SOURCES = test_group_connect.c ../src/routing_layer/topo_group_connect.c $(standby_test_sources) $(test_clock_sources)
test_group_connect_standby_CPPFLAGS = $(standby_test_cppflags)
test_group_connect_standby_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_group_connect_standby_LDFLAGS = $(test_clock_ldflags)
test_android_udp_log_SOURCES = test_android_udp_log.c ../tools/chatgui-android/jni_bridge/android_udp_log.c
test_android_udp_log_LDADD = $(COMMON_LIBS)
test_android_udp_log_LDFLAGS = -Wl,--wrap=uasync_set_timeout -Wl,--wrap=uasync_cancel_timeout
@ -548,9 +546,10 @@ test_group_recovery_SOURCES = test_group_recovery.c
test_group_recovery_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_group_recovery_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_group_connect_SOURCES = test_group_connect.c
test_group_connect_SOURCES = test_group_connect.c $(test_clock_sources)
test_group_connect_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_group_connect_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_group_connect_LDFLAGS = $(test_clock_ldflags)
test_node_snapshot_SOURCES = test_node_snapshot.c
test_node_snapshot_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib

19
tests/test_clock.c

@ -2,6 +2,7 @@
#include "../lib/debug_config.h"
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#ifdef __linux__
#include <sys/epoll.h>
@ -120,3 +121,21 @@ void test_clock_finish(void) {
(unsigned long long)advances, (unsigned long long)io_events);
#endif
}
void test_clock_next_timer(struct UASYNC* ua) {
if (!ua) { DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "test clock: null timer instance"); abort(); }
TimeoutEntry next;
for (;;) {
if (timeout_heap_peek(ua->timeout_heap, &next)) {
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "test clock: no timer to wait for"); abort();
}
if (next.expiration) break;
// Отмена помечает heap-entry нулевым expiration; освобождение оставляем штатному uasync.
uasync_poll(ua, 0);
}
uint64_t now = get_time_us(), end = next.expiration * 1000;
uint64_t duration_tb = end > now ? (end - now + 99) / 100 : 0;
if (duration_tb > INT_MAX) { DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "test clock: timer interval overflow"); abort(); }
test_clock_run_for(ua, (int)duration_tb);
uasync_poll(ua, 0);
}

2
tests/test_clock.h

@ -12,6 +12,8 @@ void test_clock_sync_wall_time(void);
void test_clock_poll(struct UASYNC* ua, int timeout_tb);
void test_clock_mainloop(struct UASYNC* ua);
void test_clock_run_for(struct UASYNC* ua, int duration_tb);
// Дождаться ближайшего неотменённого таймера; требуется хотя бы один таймер, callbacks выполняет uasync.
void test_clock_next_timer(struct UASYNC* ua);
void test_clock_finish(void);
#endif

12
tests/test_group_connect.c

@ -12,6 +12,7 @@
#include "../lib/mem.h"
#include "../lib/memory_pool.h"
#include "../lib/debug_config.h"
#include "test_clock.h"
#ifdef UTUN_HAVE_STANDBY
#include "standby.h"
#endif
@ -160,7 +161,7 @@ static void retry_done(void* arg) { *(int*)arg = 1; }
static void wait_retry(struct fixture* f) {
int done = 0;
assert(uasync_set_timeout(f->ua, 12000, &done, retry_done, "connect_test_retry"));
while (!done) uasync_poll(f->ua, 100);
while (!done) test_clock_poll(f->ua, 100);
poll_events(f);
}
@ -231,7 +232,7 @@ static void standby_down(void) {
up(&f, 0); up(&f, 1);
standby_set_intervals_ms(100, 200, 0);
assert(standby_set_enabled(f.inst, 1) == 0);
while (!standby_get_sleep_tb()) uasync_poll(f.ua, 100);
while (!standby_get_sleep_tb()) test_clock_poll(f.ua, 100);
down(&f, 0);
assert(topo_group_connect_active_count(f.group) == 1 && !peer(&f, 0) && !peer(&f, 2));
assert(standby_set_enabled(f.inst, 0) == 0); poll_events(&f);
@ -241,11 +242,11 @@ static void standby_down(void) {
create(&f, CLIENT_TYPE_MOBILE, 0);
standby_set_intervals_ms(100, 200, 0);
assert(standby_set_enabled(f.inst, 1) == 0);
while (!standby_get_sleep_tb()) uasync_poll(f.ua, 100);
while (!standby_get_sleep_tb()) test_clock_poll(f.ua, 100);
assert(topo_group_connect_init(f.group) == 0); poll_events(&f);
assert(!peer(&f, 0) && !peer(&f, 1));
/* Остаток SLEEP может обнулиться раньше доставки фазового callback. */
while (!standby_get_active_remaining_tb()) uasync_poll(f.ua, 100);
while (!standby_get_active_remaining_tb()) test_clock_poll(f.ua, 100);
poll_events(&f); assert(peer(&f, 0) && peer(&f, 1));
assert(standby_set_enabled(f.inst, 0) == 0);
destroy(&f);
@ -255,6 +256,8 @@ static void standby_down(void) {
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_BGP, DEBUG_LEVEL_INFO);
test_clock_init(1000);
test_clock_sync_wall_time();
utun_instance_set_tun_init_enabled(0);
persisted_classification();
two_supernodes();
@ -265,5 +268,6 @@ int main(void) {
standby_down();
#endif
DEBUG_INFO(DEBUG_CATEGORY_BGP, "group connect tests passed: UP, two/all supernodes, desktop/mobile fallback, retries, ownership");
test_clock_finish();
return 0;
}

13
tests/test_standby_transport.c

@ -7,6 +7,7 @@
#include "etcp_keepalive.h"
#include "standby.h"
#include "debug_config.h"
#include "test_clock.h"
static struct UASYNC* ua;
static struct UTUN_INSTANCE inst;
@ -125,7 +126,7 @@ static void check_transitions(void) {
uint64_t timers = ua->timer_alloc_count;
assert(utun_set_client_activity(&inst, 0) == 0 && ua->timer_alloc_count == timers);
assert(sent[0].count == 2 && sent[1].count == 2 && sent[2].count == 2);
uasync_poll(ua, -1); assert(standby_get_sleep_tb() > 0);
test_clock_next_timer(ua); assert(standby_get_sleep_tb() > 0);
for (int i = 0; i < 3; i++) {
etcp_keepalive_link_ready(&links[i]);
assert(sent[i].flags == KA_FLAG_SLEEP && sent[i].active == 0 && sent[i].sleep > 0 && !links[i].keepalive_timer);
@ -138,13 +139,13 @@ static void check_transitions(void) {
assert(standby_get_sleep_tb() > 0 && wait_calls == 0 && sent[0].count == wait_after_packets);
fail_phase_timer = 0;
standby_notify_network_activity(); assert(wait_calls == 1);
uasync_poll(ua, -1); assert(standby_get_sleep_tb() > 0);
test_clock_next_timer(ua); assert(standby_get_sleep_tb() > 0);
wait_after_packets = sent[0].count;
void* cancelled = standby_wait(NULL, waited); assert(cancelled);
standby_wait_cancel(cancelled);
assert(standby_wait(NULL, waited));
uasync_poll(ua, -1); assert(wait_calls == 2 && standby_get_active_remaining_tb() > 0);
uasync_poll(ua, -1); assert(standby_get_sleep_tb() > 0);
test_clock_next_timer(ua); assert(wait_calls == 2 && standby_get_active_remaining_tb() > 0);
test_clock_next_timer(ua); assert(standby_get_sleep_tb() > 0);
wait_after_packets = sent[0].count; assert(standby_wait(NULL, waited));
links[0].ka_peer_sleeping = 1;
assert(utun_set_client_activity(&inst, 1) == 0 && activity_events == 1 && wait_calls == 3);
@ -170,7 +171,7 @@ static void check_timer_failures(void) {
fail_phase_timer = 0;
assert(utun_set_client_activity(&inst, 0) == 0);
fail_phase_timer = 1;
uasync_poll(ua, -1);
test_clock_next_timer(ua);
assert(!standby_is_enabled() && inst.client_activity == CLIENT_ACTIVITY_ACTIVE && activity_events == 3);
for (int i = 0; i < 3; i++) assert(!links[i].ka_my_sleeping && links[i].keepalive_timer);
fail_phase_timer = 0; teardown();
@ -179,7 +180,9 @@ static void check_timer_failures(void) {
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
test_clock_init(1000);
check_transitions(); check_transitions(); check_timer_failures();
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "PASS: standby transport regression tests");
test_clock_finish();
return 0;
}

21
tools/chatgui-android/libutun_lite/tests/test_standby.c

@ -6,11 +6,12 @@
* пробуждение), clamp min_sleep и re-entry в wake_all_waiters.
*
* Интервалы задаются через standby_set_intervals_ms() (быстрые: 100-300мс).
* Время продвигается через uasync_poll(ua, -1) (до ближайшего таймера)
* и uasync_poll(ua, X) (частичное ожидание).
* Тестовые часы ждут ближайший таймер или заданный интервал;
* callbacks и смену фаз выполняет настоящий uasync.
*/
#include "standby.h"
#include "debug_config.h"
#include "../../../../tests/test_clock.h"
#include <stdio.h>
#include <string.h>
@ -72,12 +73,13 @@ static void reset_standby(void) {
/* продвинуть время до ближайшего таймера (фаза переключится) */
static void run_to_next_phase(void) {
uasync_poll(g_ua, -1);
test_clock_next_timer(g_ua);
}
int main(void) {
debug_config_init();
debug_set_level(DEBUG_LEVEL_INFO);
test_clock_init(1000);
g_ua = uasync_create();
if (!g_ua) { printf("uasync_create failed\n"); return 1; }
@ -133,7 +135,7 @@ int main(void) {
run_to_next_phase(); /* → SLEEP */
CHECK(standby_get_sleep_tb() > 0, "wait(SLEEP): in sleep");
standby_wait(NULL, wait_cb);
uasync_poll(g_ua, -1); /* конец сна */
run_to_next_phase(); /* конец сна */
uasync_poll(g_ua, 0);
CHECK(g_wait_calls == 1, "wait(SLEEP): fired at sleep end");
standby_set_enabled(NULL, 0);
@ -144,7 +146,7 @@ int main(void) {
run_to_next_phase(); /* → SLEEP */
void* h = standby_wait(NULL, wait_cb);
standby_wait_cancel(h);
uasync_poll(g_ua, -1); /* конец сна */
run_to_next_phase(); /* конец сна */
uasync_poll(g_ua, 0);
CHECK(g_wait_calls == 0, "wait_cancel: cb not called");
standby_set_enabled(NULL, 0);
@ -170,7 +172,7 @@ int main(void) {
CHECK(standby_get_sleep_tb() > 0, "notify(<min_sleep): still sleeping");
/* ── 13. notify в SLEEP после min_sleep → раннее пробуждение ── */
uasync_poll(g_ua, 2000); /* +200ms → прошло min_sleep(100ms) */
test_clock_run_for(g_ua, 2000); /* +200ms → прошло min_sleep(100ms) */
standby_notify_network_activity();
CHECK(standby_get_sleep_tb() == 0, "notify(>min_sleep): woke → sleep_tb 0");
CHECK(standby_get_active_remaining_tb() > 0, "notify(>min_sleep): woke → active_remaining > 0");
@ -181,7 +183,7 @@ int main(void) {
standby_set_enabled(NULL, 1);
run_to_next_phase(); /* → SLEEP */
standby_wait(NULL, wait_cb);
uasync_poll(g_ua, 2000); /* +200ms → min_sleep прошёл */
test_clock_run_for(g_ua, 2000); /* +200ms → min_sleep прошёл */
standby_notify_network_activity();
uasync_poll(g_ua, 0);
CHECK(g_wait_calls == 1, "early wake: waiter fired immediately");
@ -194,7 +196,7 @@ int main(void) {
standby_set_switch_callback(switch_cb, NULL);
standby_set_enabled(NULL, 1);
run_to_next_phase(); /* → SLEEP */
uasync_poll(g_ua, 2000); /* +200ms */
test_clock_run_for(g_ua, 2000); /* +200ms */
standby_notify_network_activity();
CHECK(standby_get_sleep_tb() > 0, "clamp: min_sleep==sleep → notify ignored");
standby_set_enabled(NULL, 0);
@ -204,7 +206,7 @@ int main(void) {
standby_set_enabled(NULL, 1);
run_to_next_phase(); /* → SLEEP */
standby_wait(NULL, reentry_cb);
uasync_poll(g_ua, 2000); /* +200ms → min_sleep прошёл */
test_clock_run_for(g_ua, 2000); /* +200ms → min_sleep прошёл */
standby_notify_network_activity(); /* раннее пробуждение → wake_all_waiters */
CHECK(g_reentry_calls == 1, "re-entry: wake fired waiter once (no infinite loop)");
CHECK(standby_is_enabled() == 1, "re-entry: still enabled after early wake");
@ -238,5 +240,6 @@ int main(void) {
printf("=== standby unit test: %d checks, %d failures ===\n", g_checks, g_failures);
if (g_failures == 0) printf("PASS\n");
else printf("FAIL\n");
test_clock_finish();
return g_failures ? 1 : 0;
}

Loading…
Cancel
Save