Files
utun2/tests/async_regression.h
T

62 lines
5.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Linux/ELF-стенд регрессий: regression_run запускает каждый случай в fork с лимитом 2000мс реального времени.
* Падение/зависание не скрывает остальные случаи; успешный случай дополнительно проверяется на u_* и fd-утечки.
* Снимки fd читаются из /proc/self/fd; если proc недоступен, этот контроль не работает.
* fault/clock/epoll работают через --wrap из async_regression_ldflags в tests/Makefile.am.
* Состояние подмен глобально, без синхронизации; не менять его параллельно с использующими его вызовами.
* Это отдельный стенд, его clock wrapper нельзя совмещать с wrappers test_clock.c в одном бинарнике. */
#ifndef ASYNC_REGRESSION_H
#define ASYNC_REGRESSION_H
#include "../lib/u_async.h"
#include "../lib/ll_queue.h"
#include "../lib/mem.h"
#include <stdio.h>
#include <sys/epoll.h>
/* Проверки вычисляют аргументы по одному разу; при отказе печатают место/условие и возвращают 1 из run.
* CHECK_EQ сравнивает после преобразования к long long; макросы не выполняют cleanup случая. */
#define CHECK(cond) do { if (!(cond)) { \
fprintf(stderr, "[FAIL] %s:%d: %s\n", __FILE__, __LINE__, #cond); return 1; \
} } while (0)
#define CHECK_EQ(actual, expected) do { \
long long a_ = (long long)(actual), e_ = (long long)(expected); \
if (a_ != e_) { fprintf(stderr, "[FAIL] %s:%d: %s=%lld expected=%lld\n", \
__FILE__, __LINE__, #actual, a_, e_); return 1; } \
} while (0)
struct regression_case {
const char* name; // Заимствованное имя для вывода и фильтра по подстроке, живёт до возврата regression_run.
int (*run)(int param); // Выполняется в дочернем процессе: 0 — успех, 77 — skip, прочие коды — ошибка.
int param; // Параметр конкретного случая, передаётся run без преобразования.
};
/* argc/argv — main: необязательный argv[1] фильтрует имена по подстроке; таблица cases заимствуется на вызов.
* Возврат 0 — все выбранные прошли/skip, 1 — ошибка/timeout/signal, нет совпадений или неверные аргументы.
* Вывод ребёнка наследует stdout/stderr; ресурсный контроль выполняется только для run=0. */
int regression_run(int argc, char** argv, const struct regression_case* cases, size_t count);
// CLOCK_MONOTONIC в мс, независимо от regression_clock_shift; ошибка часов завершает процесс через abort.
uint64_t regression_time_ms(void);
// WARN для всех категорий; наличие UTUN_TEST_DEBUG добавляет DEBUG для sys/socket/timers. Вызывает и сам runner в ребёнке.
void regression_log_init(void);
enum regression_alloc { FAULT_MALLOC = 1, FAULT_CALLOC = 2, FAULT_REALLOC = 4, FAULT_ALLOC = 7 };
/* Отказ u_malloc/u_calloc/u_realloc из mask: scope — подстрока allocation location либо NULL для всех мест.
* nth=0 — все совпавшие выделения до reset, nth>0 — только N-е совпавшее. scope заимствуется на время подмены.
* arm сбрасывает признак hit; отказ выдаёт NULL и [INJECT] с местом. Обычный malloc не перехватывается. */
void regression_fault_arm(int mask, const char* scope, int nth);
// Был хотя бы один отказ после последнего arm (0/1), не число отказов.
int regression_fault_hit(void);
// Только отключить allocation faults; hit, часы и прочие подмены не сбрасываются.
void regression_fault_reset(void);
// Заменить поправку gettimeofday в мс (0 отключает), не менять CLOCK_REALTIME/MONOTONIC или часы ОС.
void regression_clock_shift(int64_t milliseconds);
// Скопировать 0..64 события и один раз вернуть их следующим epoll_wait; нужен maxevents>=count. Новый вызов заменяет пакет.
void regression_epoll_events(const struct epoll_event* events, int count);
// Один отказ следующего epoll_ctl с данным EPOLL_CTL_* (ENOMEM); operation=0 снимает эту подмену.
void regression_epoll_ctl_fail(int operation);
// Один отказ следующего eventfd/epoll_create1 с errno=EMFILE.
void regression_eventfd_fail(void);
void regression_epoll_create_fail(void);
#endif