Browse Source

tests: replace slow disk sleep with six-second clock-driven gate

master
evgeny 3 days ago
parent
commit
0448a84286
  1. 3
      tests/Makefile.am
  2. 51
      tests/test_member_files_network.c

3
tests/Makefile.am

@ -785,9 +785,10 @@ test_services_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_member_files_SOURCES = test_member_files.c
test_member_files_CFLAGS = $(test_services_CFLAGS)
test_member_files_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_member_files_network_SOURCES = test_member_files_network.c
test_member_files_network_SOURCES = test_member_files_network.c $(test_clock_sources)
test_member_files_network_CFLAGS = $(test_services_CFLAGS)
test_member_files_network_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_member_files_network_LDFLAGS = $(test_clock_ldflags)
test_group_avatar_SOURCES = test_group_avatar.c
test_group_avatar_CFLAGS = $(test_services_CFLAGS)
test_group_avatar_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)

51
tests/test_member_files_network.c

@ -13,9 +13,11 @@
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#include "test_utils.h"
#include "test_clock.h"
#include <openssl/sha.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#define GROUP 5858585858585858ULL
#define CHANNEL "5858585858585858"
@ -38,6 +40,10 @@ struct network_test {
unsigned phase, ticks, progress;
int answered, finished, transfer_status, failed;
int slow_queued, slow_done, receive_pauses;
pthread_mutex_t disk_mutex;
pthread_cond_t disk_condition;
uint64_t disk_started_tb;
int disk_released, disk_error;
unsigned peak_inflight;
int (*saved_receive_ready)(struct UTUN_INSTANCE*, uint64_t, uint64_t, const uint8_t*, size_t);
unsigned restart_tick;
@ -53,16 +59,20 @@ static void fail(struct network_test* t, const char* why) {
static void hex(const uint8_t* input, char* out) { for (unsigned i = 0; i < 32; i++) snprintf(out + 2 * i, 3, "%02x", input[i]); }
static void slow_disk(void* arg) {
(void)arg;
#ifdef _WIN32
Sleep(6000);
#else
struct timespec delay = {6, 0}; nanosleep(&delay, NULL);
#endif
struct network_test* t = arg;
pthread_mutex_lock(&t->disk_mutex);
t->disk_started_tb = get_time_tb();
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "member_files test: disk worker blocked started_tb=%llu",
(unsigned long long)t->disk_started_tb);
while (!t->disk_released) {
int rc = pthread_cond_wait(&t->disk_condition, &t->disk_mutex);
if (rc) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "member_files test: disk wait failed rc=%d", rc); t->disk_error = rc; break; }
}
pthread_mutex_unlock(&t->disk_mutex);
}
static void slow_done(void* arg, int error) {
struct network_test* t = arg;
if (error) fail(t, "slow disk task rejected");
if (error || t->disk_error) fail(t, "slow disk task rejected or wait failed");
t->slow_done = 1;
}
static void capture_log(int level, const char* category, const char* message) {
@ -197,6 +207,15 @@ static int downloaded(struct network_test* t) {
static void tick(void* arg) {
struct network_test* t = arg; t->timer = NULL;
if (++t->ticks > 6000) { fail(t, "60s deadline"); return; }
// Отсчитываем полные 6с от фактической блокировки worker, не от постановки задания.
pthread_mutex_lock(&t->disk_mutex);
if (t->disk_started_tb && !t->disk_released && get_time_tb() - t->disk_started_tb >= 60000) {
t->disk_released = 1;
pthread_cond_signal(&t->disk_condition);
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "member_files test: disk released elapsed_tb=%llu receive_pauses=%d peak_inflight=%u",
(unsigned long long)(get_time_tb() - t->disk_started_tb), t->receive_pauses, t->peak_inflight);
}
pthread_mutex_unlock(&t->disk_mutex);
struct ETCP_ROUTER_CONN* route = etcp_router_conn_get(t->nodes[AUTHOR], GROUP, t->ids[SERVER], ETCP_RT_ID_MEMBER_FILES);
if (route->inflight_q->count > t->peak_inflight) t->peak_inflight = route->inflight_q->count;
if (t->phase == 0) {
@ -304,10 +323,11 @@ again:
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR); debug_set_category_level(DEBUG_CATEGORY_MEDIA, DEBUG_LEVEL_DEBUG);
test_clock_init(1000);
debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_TRACE);
debug_set_category_level(DEBUG_CATEGORY_ETCPROUTE, DEBUG_LEVEL_DEBUG);
utun_instance_set_tun_init_enabled(0);
struct network_test t = {0}; active = &t;
struct network_test t = { .disk_mutex = PTHREAD_MUTEX_INITIALIZER, .disk_condition = PTHREAD_COND_INITIALIZER }; active = &t;
debug_set_log_hook(capture_log);
snprintf(t.dir, sizeof(t.dir), "/tmp/utun_member_files_net_XXXXXX");
if (test_mkdtemp(t.dir)) return 1;
@ -316,28 +336,29 @@ int main(void) {
int port = 39000 + (int)(get_time_tb() % 8000);
for (unsigned i = 0; i < NODE_COUNT; i++) if (start(&t, i, port)) { t.failed = 1; goto stop; }
if (setup(&t)) { t.failed = 1; goto stop; }
t.timer = uasync_set_timeout(t.ua, 100, &t, tick, "member_files_test"); uasync_mainloop(t.ua);
t.timer = uasync_set_timeout(t.ua, 100, &t, tick, "member_files_test"); test_clock_mainloop(t.ua);
if (!t.failed) {
// Stop/destroy вне callbacks: server cleanup ещё использует storage после текущего I/O.
api_start(&t, 0, AUTHOR, 1, "stop.bin", t.source);
api_start(&t, 1, AUTHOR, 0, "file.bin", NULL);
uint64_t deadline = get_time_tb() + 50000;
while (!t.nodes[SERVER]->member_files->server_transfer_count && get_time_tb() < deadline) {
uasync_poll(t.ua, 0);
#ifdef _WIN32
Sleep(1);
#else
struct timespec delay = {0, 1000000}; nanosleep(&delay, NULL);
#endif
test_clock_poll(t.ua, 10);
}
if (!t.nodes[SERVER]->member_files->server_transfer_count) fail(&t, "server stream did not start before teardown");
}
stop:
if (t.timer) uasync_cancel_timeout(t.ua, t.timer);
// При ошибке сценария освобождаем worker до destroy, иначе drain будет ждать блокировку.
pthread_mutex_lock(&t.disk_mutex);
t.disk_released = 1; pthread_cond_signal(&t.disk_condition);
pthread_mutex_unlock(&t.disk_mutex);
for (unsigned i = 0; i < NODE_COUNT; i++) if (t.nodes[i]) utun_instance_destroy(t.nodes[i]);
if (!t.failed && (!t.api[0].finished || !t.api[1].finished || t.api[0].status != MF_CANCELLED || t.api[1].status != MF_CANCELLED))
t.failed = 1;
uasync_destroy(t.ua, 0);
pthread_cond_destroy(&t.disk_condition); pthread_mutex_destroy(&t.disk_mutex);
debug_set_log_hook(NULL);
test_clock_finish();
printf("member_files network: %s phase=%u\n", t.failed ? "FAIL" : "PASS", t.phase); return t.failed;
}

Loading…
Cancel
Save