You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
4.3 KiB
86 lines
4.3 KiB
/* Настоящий CLI без -f: daemon должен создать disk worker после fork, завершиться |
|
* по SIGTERM и вернуть launcher ошибку, если PID-файл нельзя создать. Без настоящего TUN. */ |
|
#include "../lib/platform_compat.h" |
|
#include "../lib/u_async.h" |
|
#include "../lib/debug_config.h" |
|
#include "test_utils.h" |
|
#include <stdio.h> |
|
#include <string.h> |
|
#ifdef __linux__ |
|
#include <dirent.h> |
|
#include <spawn.h> |
|
#include <sys/wait.h> |
|
#include <signal.h> |
|
extern char** environ; |
|
|
|
static int launch(const char* config, const char* pidfile, const char* log) { |
|
char* argv[] = { UTUN_CLI_PATH, "-c", (char*)config, "-p", (char*)pidfile, "-l", (char*)log, |
|
"-d", "sys=info,debug=trace", NULL }; |
|
pid_t launcher; |
|
int error = posix_spawn(&launcher, UTUN_CLI_PATH, NULL, NULL, argv, environ); |
|
if (error) { DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: spawn failed error=%d", error); return -1; } |
|
int status; |
|
while (waitpid(launcher, &status, 0) < 0) { |
|
if (errno == EINTR) continue; |
|
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: waitpid failed: %s", strerror(errno)); return -1; |
|
} |
|
return WIFEXITED(status) ? WEXITSTATUS(status) : -1; |
|
} |
|
|
|
static int thread_count(pid_t pid) { |
|
char path[128]; snprintf(path, sizeof(path), "/proc/%ld/task", (long)pid); |
|
DIR* dir = opendir(path); |
|
if (!dir) { DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: task listing failed: %s", strerror(errno)); return -1; } |
|
int count = 0; struct dirent* entry; |
|
while ((entry = readdir(dir))) if (entry->d_name[0] != '.') count++; |
|
closedir(dir); return count; |
|
} |
|
|
|
static int stop(pid_t pid, const char* pidfile) { |
|
if (kill(pid, SIGTERM)) { DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: SIGTERM failed: %s", strerror(errno)); return -1; } |
|
uint64_t deadline = get_time_tb() + 20000; |
|
while (access(pidfile, F_OK) == 0 && get_time_tb() < deadline) poll(NULL, 0, 10); |
|
if (access(pidfile, F_OK) == 0) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: shutdown stuck pid=%ld; killing own fixture", (long)pid); |
|
if (kill(pid, SIGKILL)) DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: fixture cleanup failed: %s", strerror(errno)); |
|
return -1; |
|
} |
|
return 0; |
|
} |
|
|
|
int main(void) { |
|
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); |
|
char dir[512] = "/tmp/utun_daemon_worker_XXXXXX"; |
|
if (test_mkdtemp(dir)) return 1; |
|
char config[768], pidfile[768], log[768], bad_pid[768]; |
|
snprintf(config, sizeof(config), "%s/utun.conf", dir); snprintf(pidfile, sizeof(pidfile), "%s/daemon.pid", dir); |
|
snprintf(log, sizeof(log), "%s/daemon.log", dir); snprintf(bad_pid, sizeof(bad_pid), "%s/missing/daemon.pid", dir); |
|
FILE* f = fopen(config, "w"); if (!f) return 1; |
|
fprintf(f, "[global]\nmy_private_key=704f2e012c8fa8768130cb0f988a997dccb628372bc5ceccacc78dcbfec5916f\n" |
|
"my_public_key=b3193173def895bd0fcea6f86af077c7d77216f10395275f627ac18242ec0f01\n" |
|
"tun_ip=192.0.2.1\ntun_test_mode=1\n" |
|
"[server:test]\naddr=127.0.0.1:0\ntype=private\n" |
|
"[chatserver]\ndb_path=%s/db\nstorage_autoload=0\ngroup_autoconnect=0\n", dir); |
|
if (fclose(f) || launch(config, pidfile, log)) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: startup failed log=%s", log); return 1; |
|
} |
|
f = fopen(pidfile, "r"); long value = 0; |
|
if (!f || fscanf(f, "%ld", &value) != 1 || value <= 1) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: invalid/missing pidfile=%s", pidfile); if (f) fclose(f); return 1; |
|
} |
|
fclose(f); pid_t daemon_pid = (pid_t)value; |
|
int threads = thread_count(daemon_pid); |
|
int stopped = stop(daemon_pid, pidfile); |
|
if (threads < 2 || stopped) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: worker lost or shutdown failed threads=%d stopped=%d log=%s", threads, stopped, log); |
|
return 1; |
|
} |
|
if (launch(config, bad_pid, log) == 0) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "daemon test: launcher accepted failed child initialization log=%s", log); return 1; |
|
} |
|
printf("daemon worker: PASS threads=%d, graceful shutdown, startup errors propagate\n", threads); |
|
return 0; |
|
} |
|
#else |
|
int main(void) { printf("daemon worker: SKIP (requires Linux procfs)\n"); return 77; } |
|
#endif
|
|
|