#include "u_async.h" #include "ll_queue.h" #include "pkt_normalizer.h" #include "u_async.h" #include "settings.h" #include #include #include #include #include #include #define TEST_ASSERT(cond, msg) \ do { \ if (!(cond)) { \ printf("FAIL: %s (line %d)\n", msg, __LINE__); \ return 1; \ } else { \ printf("PASS: %s\n", msg); \ } \ } while(0) /* Структура для хранения тестового пакета */ typedef struct { uint8_t* data; size_t len; } test_packet_t; #define MAX_TEST_PACKETS 20000 static test_packet_t sent_packets[MAX_TEST_PACKETS]; static test_packet_t received_packets[MAX_TEST_PACKETS]; static int sent_count = 0; static int received_count = 0; static uasync_t* test_ua = NULL; static void reset_test_data(void) { for (int i = 0; i < sent_count; i++) { free(sent_packets[i].data); sent_packets[i].data = NULL; } for (int i = 0; i < received_count; i++) { free(received_packets[i].data); received_packets[i].data = NULL; } sent_count = 0; received_count = 0; } static void add_sent_packet(const uint8_t* data, size_t len) { assert(sent_count < MAX_TEST_PACKETS); sent_packets[sent_count].data = malloc(len); assert(sent_packets[sent_count].data); memcpy(sent_packets[sent_count].data, data, len); sent_packets[sent_count].len = len; sent_count++; } static void add_received_packet(const uint8_t* data, size_t len) { assert(received_count < MAX_TEST_PACKETS); received_packets[received_count].data = malloc(len); assert(received_packets[received_count].data); memcpy(received_packets[received_count].data, data, len); received_packets[received_count].len = len; received_count++; } static int compare_packets(void) { if (sent_count != received_count) { printf("Packet count mismatch: sent=%d, received=%d\n", sent_count, received_count); return -1; } for (int i = 0; i < sent_count; i++) { if (sent_packets[i].len != received_packets[i].len) { printf("Packet %d length mismatch: sent=%zu, received=%zu\n", i, sent_packets[i].len, received_packets[i].len); return -1; } if (memcmp(sent_packets[i].data, received_packets[i].data, sent_packets[i].len) != 0) { printf("Packet %d data mismatch\n", i); return -1; } } return 0; } /* Создать тестовый пакет со случайным содержимым */ static ll_entry_t* create_test_packet(size_t data_size) { ll_entry_t* entry = queue_entry_new(data_size); if (!entry) { return NULL; } uint8_t* data = ll_entry_data(entry); for (size_t i = 0; i < data_size; i++) { data[i] = rand() & 0xFF; } return entry; } /* Коллбэк для пересылки пакетов от упаковщика к распаковщику */ static void forward_cb(ll_queue_t* q, ll_entry_t* unused, void* arg) { (void)unused; ll_queue_t* target = (ll_queue_t*)arg; while (queue_entry_count(q) > 0) { ll_entry_t* e = queue_entry_get(q); queue_entry_put(target, e); // Transfer ownership } queue_resume_callback(q); } /* Коллбэк для сбора полученных пакетов */ static void receive_cb(ll_queue_t* q, ll_entry_t* unused, void* arg) { (void)unused; (void)arg; while (queue_entry_count(q) > 0) { ll_entry_t* e = queue_entry_get(q); uint8_t* data = ll_entry_data(e); size_t len = ll_entry_size(e); add_received_packet(data, len); queue_entry_free(e); } queue_resume_callback(q); } /* Принудительно обработать все очереди, вызывая коллбэки для непустых очередей * Это нужно потому что в тестовой среде нет uasync_mainloop */ static void process_queues(pkt_normalizer_pair* pair) { int iterations = 0; int processed; /* Сначала принудительно сбросим все флаги callback_suspended, потому что * uasync таймауты не работают в тестовой среде */ pair->packer->input->callback_suspended = 0; pair->packer->output->callback_suspended = 0; pair->unpacker->input->callback_suspended = 0; pair->unpacker->output->callback_suspended = 0; do { processed = 0; iterations++; if (iterations % 10 == 1) printf("process_queues iteration %d: counts: pi=%d po=%d ui=%d uo=%d\n", iterations, queue_entry_count(pair->packer->input), queue_entry_count(pair->packer->output), queue_entry_count(pair->unpacker->input), queue_entry_count(pair->unpacker->output)); /* Обработать входную очередь упаковщика */ while (pair->packer->input->callback && queue_entry_count(pair->packer->input) > 0) { pair->packer->input->callback(pair->packer->input, pair->packer->input->head, pair->packer->input->callback_arg); processed = 1; } /* Обработать выходную очередь упаковщика (forward_cb) */ if (pair->packer->output->callback && queue_entry_count(pair->packer->output) > 0) { pair->packer->output->callback(pair->packer->output, pair->packer->output->head, pair->packer->output->callback_arg); processed = 1; } /* Обработать входную очередь распаковщика */ if (pair->unpacker->input->callback && queue_entry_count(pair->unpacker->input) > 0) { pair->unpacker->input->callback(pair->unpacker->input, pair->unpacker->input->head, pair->unpacker->input->callback_arg); processed = 1; } /* Обработать выходную очередь распаковщика (receive_cb) */ if (pair->unpacker->output->callback && queue_entry_count(pair->unpacker->output) > 0) { pair->unpacker->output->callback(pair->unpacker->output, pair->unpacker->output->head, pair->unpacker->output->callback_arg); processed = 1; } if (iterations > 100000) { printf("ERROR: process_queues infinite loop detected\n"); break; } } while (processed); } /* Тест 1: мелкие пакеты */ static int test_small_packets(pkt_normalizer_pair* pair) { printf("\n--- Test 1: small packets ---\n"); reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); const char* packets[] = {"hello", "world", "test"}; for (size_t i = 0; i < sizeof(packets)/sizeof(packets[0]); i++) { size_t len = strlen(packets[i]); ll_entry_t* entry = queue_entry_new(len); TEST_ASSERT(entry != NULL, "create packet"); memcpy(ll_entry_data(entry), packets[i], len); add_sent_packet((const uint8_t*)packets[i], len); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put into packer input"); } process_queues(pair); TEST_ASSERT(compare_packets() == 0, "small packets comparison"); return 0; } /* Тест 2: средний пакет (не фрагментируется) */ static int test_medium_packet(pkt_normalizer_pair* pair) { printf("\n--- Test 2: medium packet ---\n"); reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); size_t data_size = 500; ll_entry_t* entry = create_test_packet(data_size); TEST_ASSERT(entry != NULL, "create medium packet"); uint8_t* data = ll_entry_data(entry); add_sent_packet(data, data_size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put medium packet"); process_queues(pair); TEST_ASSERT(compare_packets() == 0, "medium packet comparison"); return 0; } /* Тест 3: большой пакет с фрагментацией */ static int test_fragmentation(pkt_normalizer_pair* pair) { printf("\n--- Test 3: fragmentation ---\n"); reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); /* Сохранить оригинальный размер фрагмента */ int original_fragment_size = settings.max_fragment_size; /* Установить маленький размер фрагмента для тестирования */ settings.max_fragment_size = 300; size_t data_size = 1000; /* Должен быть фрагментирован */ ll_entry_t* entry = create_test_packet(data_size); TEST_ASSERT(entry != NULL, "create big packet"); uint8_t* data = ll_entry_data(entry); add_sent_packet(data, data_size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put big packet"); process_queues(pair); /* Проверить, что не было ошибок сборки */ TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no fragmentation errors"); /* Восстановить оригинальный размер */ settings.max_fragment_size = original_fragment_size; TEST_ASSERT(compare_packets() == 0, "fragmented packet comparison"); return 0; } /* Тест 4: несколько пакетов разного размера */ static int test_mixed_packets(pkt_normalizer_pair* pair) { printf("\n--- Test 4: mixed size packets ---\n"); reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); /* Отправить пакеты разных размеров */ size_t sizes[] = {10, 100, 50, 300, 5}; for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++) { ll_entry_t* entry = create_test_packet(sizes[i]); TEST_ASSERT(entry != NULL, "create mixed packet"); uint8_t* data = ll_entry_data(entry); add_sent_packet(data, sizes[i]); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put mixed packet"); } process_queues(pair); TEST_ASSERT(compare_packets() == 0, "mixed packets comparison"); return 0; } /* Тест 6: стресс-тест со случайными размерами пакетов */ static int test_stress_random(pkt_normalizer_pair* pair) { printf("\n--- Test 6: stress test with 10000 random packets (0-4096 bytes) ---\n"); const int NUM_PACKETS = 10000; const int MAX_PACKET_SIZE = 4096; int original_fragment_size = settings.max_fragment_size; /* Часть 1: 10000 случайных пакетов без изменения размера фрагмента */ printf("Sending %d random packets...\n", NUM_PACKETS); reset_test_data(); pkt_normalizer_reset_error_count(pair->packer); pkt_normalizer_reset_error_count(pair->unpacker); for (int i = 0; i < NUM_PACKETS; i++) { /* Случайный размер пакета от 0 до MAX_PACKET_SIZE */ size_t size = rand() % (MAX_PACKET_SIZE + 1); ll_entry_t* entry = create_test_packet(size); TEST_ASSERT(entry != NULL, "create random packet"); uint8_t* data = ll_entry_data(entry); add_sent_packet(data, size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put random packet"); // Периодически обрабатывать очереди чтобы не переполнять if (i % 500 == 0) { process_queues(pair); } // Прогресс if (i % 1000 == 0) { printf(" Progress: %d/%d sent=%d received=%d pi=%d po=%d ui=%d uo=%d\n", i, NUM_PACKETS, sent_count, received_count, queue_entry_count(pair->packer->input), queue_entry_count(pair->packer->output), queue_entry_count(pair->unpacker->input), queue_entry_count(pair->unpacker->output)); } } // Обработать оставшиеся пакеты process_queues(pair); printf("Sent %d packets, received %d packets\n", sent_count, received_count); TEST_ASSERT(sent_count == NUM_PACKETS, "all packets sent"); TEST_ASSERT(received_count == NUM_PACKETS, "all packets received"); TEST_ASSERT(compare_packets() == 0, "all packets matched"); printf("Packer error count: %d\n", pkt_normalizer_get_error_count(pair->packer)); printf("Unpacker error count: %d\n", pkt_normalizer_get_error_count(pair->unpacker)); TEST_ASSERT(pkt_normalizer_get_error_count(pair->packer) <= 10, "too many packer errors"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no unpacker errors"); /* Часть 2: проверка дефрагментации (большой пакет фрагментируется, а не отправляется мелкими пакетами) */ printf("\n--- Verifying fragmentation behavior ---\n"); settings.max_fragment_size = 500; reset_test_data(); pkt_normalizer_reset_error_count(pair->packer); pkt_normalizer_reset_error_count(pair->unpacker); // Большой пакет, который должен быть фрагментирован size_t big_packet_size = 2000; ll_entry_t* entry = create_test_packet(big_packet_size); TEST_ASSERT(entry != NULL, "create big packet"); add_sent_packet(ll_entry_data(entry), big_packet_size); // Подсчитать количество элементов в output очереди packer'а до обработки int initial_output_count = queue_entry_count(pair->packer->output); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put big packet"); // Обработать только packer (чтобы фрагменты появились в его output) if (pair->packer->input->callback && queue_entry_count(pair->packer->input) > 0) { pair->packer->input->callback(pair->packer->input, pair->packer->input->head, pair->packer->input->callback_arg); } // Проверить количество фрагментов в output очереди packer'а int fragment_count = queue_entry_count(pair->packer->output); printf("Big packet %zu bytes, fragment size %d, produced %d fragments\n", big_packet_size, settings.max_fragment_size, fragment_count); // Должно быть больше 1 фрагмента TEST_ASSERT(fragment_count > 1, "packet was fragmented"); // Ожидаемое количество фрагментов: ceil(2000 / (500 - overhead)) TEST_ASSERT(fragment_count >= 3 && fragment_count <= 6, "reasonable fragment count"); // Теперь обработать все фрагменты через unpacker и проверить сборку process_queues(pair); TEST_ASSERT(compare_packets() == 0, "fragmented packet correctly reassembled"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no unpacker errors"); /* Часть 3: проверка отправки буфера при пустой входной очереди */ printf("\n--- Verifying buffer flush on empty input queue ---\n"); settings.max_fragment_size = 500; reset_test_data(); pkt_normalizer_reset_error_count(pair->packer); pkt_normalizer_reset_error_count(pair->unpacker); // Отправить маленький пакет, который поместится в буфер packer'а size_t small_size = 100; ll_entry_t* entry1 = create_test_packet(small_size); TEST_ASSERT(entry1 != NULL, "create first small packet"); add_sent_packet(ll_entry_data(entry1), small_size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry1) == 0, "put first packet"); // Обработать packer input (пакет должен добавиться в буфер, но не отправиться) if (pair->packer->input->callback && queue_entry_count(pair->packer->input) > 0) { pair->packer->input->callback(pair->packer->input, pair->packer->input->head, pair->packer->input->callback_arg); } // Проверить, что в output очереди ничего нет (пакет ещё не отправлен) int output_before = queue_entry_count(pair->packer->output); printf("After first packet: packer output queue count = %d\n", output_before); // Отправим второй маленький пакет, который заставит packer отправить буфер ll_entry_t* entry2 = create_test_packet(small_size); TEST_ASSERT(entry2 != NULL, "create second small packet"); add_sent_packet(ll_entry_data(entry2), small_size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry2) == 0, "put second packet"); // Обработать packer input if (pair->packer->input->callback && queue_entry_count(pair->packer->input) > 0) { pair->packer->input->callback(pair->packer->input, pair->packer->input->head, pair->packer->input->callback_arg); } // Теперь в output должна быть хотя бы одна запись (буфер отправлен) int output_after = queue_entry_count(pair->packer->output); printf("After second packet: packer output queue count = %d\n", output_after); TEST_ASSERT(output_after > output_before, "buffer flushed when new packet arrives"); // Обработать все оставшиеся очереди process_queues(pair); TEST_ASSERT(compare_packets() == 0, "both packets correctly processed"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no unpacker errors"); settings.max_fragment_size = original_fragment_size; return 0; } /* Тест 7: граничные случаи и максимальные размеры */ static int test_edge_cases(pkt_normalizer_pair* pair) { printf("\n--- Test 7: edge cases and maximum sizes ---\n"); int original_fragment_size = settings.max_fragment_size; /* Сбросить данные теста */ reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); pkt_normalizer_flush(pair->packer); /* Тест 1: минимальный размер пакета (1 байт) */ { size_t size = 1; ll_entry_t* entry = create_test_packet(size); TEST_ASSERT(entry != NULL, "create 1-byte packet"); add_sent_packet(ll_entry_data(entry), size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 1-byte packet"); process_queues(pair); TEST_ASSERT(compare_packets() == 0, "1-byte packet comparison"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 1-byte packet"); } /* Тест 2: граница одно- и двухбайтного заголовка (239/240) */ { reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); pkt_normalizer_flush(pair->packer); size_t size = 239; ll_entry_t* entry = create_test_packet(size); TEST_ASSERT(entry != NULL, "create 239-byte packet"); add_sent_packet(ll_entry_data(entry), size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 239-byte packet"); process_queues(pair); TEST_ASSERT(compare_packets() == 0, "239-byte packet comparison"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 239-byte packet"); } { reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); size_t size = 240; ll_entry_t* entry = create_test_packet(size); TEST_ASSERT(entry != NULL, "create 240-byte packet"); add_sent_packet(ll_entry_data(entry), size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 240-byte packet"); process_queues(pair); TEST_ASSERT(compare_packets() == 0, "240-byte packet comparison"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 240-byte packet"); } /* Тест 3: максимальный размер без фрагментации (3839) */ { reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); pkt_normalizer_flush(pair->packer); size_t size = 3839; ll_entry_t* entry = create_test_packet(size); TEST_ASSERT(entry != NULL, "create 3839-byte packet"); add_sent_packet(ll_entry_data(entry), size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 3839-byte packet"); process_queues(pair); TEST_ASSERT(compare_packets() == 0, "3839-byte packet comparison"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 3839-byte packet"); } /* Тест 4: размер, требующий фрагментации (3840) с обычным max_fragment_size */ { reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); pkt_normalizer_flush(pair->packer); size_t size = 3840; ll_entry_t* entry = create_test_packet(size); TEST_ASSERT(entry != NULL, "create 3840-byte packet"); add_sent_packet(ll_entry_data(entry), size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 3840-byte packet"); process_queues(pair); TEST_ASSERT(compare_packets() == 0, "3840-byte packet comparison"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 3840-byte packet"); } /* Тест 5: размер чуть меньше max_fragment_size, чтобы не фрагментироваться */ { reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); pkt_normalizer_flush(pair->packer); settings.max_fragment_size = 500; size_t size = 480; /* достаточно мало, чтобы поместиться с заголовком */ ll_entry_t* entry = create_test_packet(size); TEST_ASSERT(entry != NULL, "create 480-byte packet with fragment size 500"); add_sent_packet(ll_entry_data(entry), size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put packet"); process_queues(pair); TEST_ASSERT(compare_packets() == 0, "packet comparison with fragment size 500"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors"); } /* Тест 6: размер чуть больше max_fragment_size, чтобы вызвать фрагментацию */ { reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); pkt_normalizer_flush(pair->packer); settings.max_fragment_size = 500; size_t size = 520; /* потребует фрагментации */ ll_entry_t* entry = create_test_packet(size); TEST_ASSERT(entry != NULL, "create 520-byte packet with fragment size 500"); add_sent_packet(ll_entry_data(entry), size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put packet"); process_queues(pair); TEST_ASSERT(compare_packets() == 0, "packet comparison with fragmentation"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors"); } /* Тест 7: максимальный размер пакета с фрагментации (65535) - ограничим 10000 для скорости */ { reset_test_data(); pkt_normalizer_reset_error_count(pair->unpacker); pkt_normalizer_flush(pair->packer); settings.max_fragment_size = 1000; size_t size = 10000; ll_entry_t* entry = create_test_packet(size); TEST_ASSERT(entry != NULL, "create 10000-byte fragmented packet"); add_sent_packet(ll_entry_data(entry), size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put large fragmented packet"); process_queues(pair); TEST_ASSERT(compare_packets() == 0, "large fragmented packet comparison"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for large fragmented packet"); } settings.max_fragment_size = original_fragment_size; return 0; } /* Тест 8: 10000 пакетов случайного размера (1-1024 байт) */ /* Тест 9: проверка дефрагментации (большой пакет фрагментируется, не отправляется мелкими пакетами) */ static int test_fragmentation_verify(pkt_normalizer_pair* pair) { printf("\n--- Test 9: fragmentation verification ---\n"); int original_fragment_size = settings.max_fragment_size; // Установить маленький размер фрагмента для теста settings.max_fragment_size = 500; reset_test_data(); pkt_normalizer_reset_error_count(pair->packer); pkt_normalizer_reset_error_count(pair->unpacker); // Большой пакет, который должен быть фрагментирован size_t big_packet_size = 2000; // Должен быть разбит на ~4 фрагмента (500 байт каждый с накладными расходами) ll_entry_t* entry = create_test_packet(big_packet_size); TEST_ASSERT(entry != NULL, "create big packet"); add_sent_packet(ll_entry_data(entry), big_packet_size); // Подсчитать количество элементов в output очереди packer'а до обработки int initial_output_count = queue_entry_count(pair->packer->output); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put big packet"); // Обработать только packer (чтобы фрагменты появились в его output) // Вместо process_queues вызовем обработку только packer input и output if (pair->packer->input->callback && queue_entry_count(pair->packer->input) > 0) { pair->packer->input->callback(pair->packer->input, pair->packer->input->head, pair->packer->input->callback_arg); } // Проверить количество фрагментов в output очереди packer'а int fragment_count = queue_entry_count(pair->packer->output); printf("Big packet %zu bytes, fragment size %d, produced %d fragments\n", big_packet_size, settings.max_fragment_size, fragment_count); // Должно быть больше 1 фрагмента TEST_ASSERT(fragment_count > 1, "packet was fragmented"); // Ожидаемое количество фрагментов: ceil(2000 / (500 - overhead)) // overhead зависит от заголовков. Минимум 1 байт заголовка на фрагмент + 2 байта длины // Приблизительно 4-5 фрагментов TEST_ASSERT(fragment_count >= 3 && fragment_count <= 6, "reasonable fragment count"); // Теперь обработать все фрагменты через unpacker и проверить сборку process_queues(pair); TEST_ASSERT(compare_packets() == 0, "fragmented packet correctly reassembled"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no unpacker errors"); settings.max_fragment_size = original_fragment_size; return 0; } /* Тест 10: проверка отправки буфера при пустой входной очереди */ static int test_empty_queue_flush(pkt_normalizer_pair* pair) { printf("\n--- Test 10: empty queue buffer flush ---\n"); int original_fragment_size = settings.max_fragment_size; settings.max_fragment_size = 500; reset_test_data(); pkt_normalizer_reset_error_count(pair->packer); pkt_normalizer_reset_error_count(pair->unpacker); // Отправить маленький пакет, который поместится в буфер packer'а size_t small_size = 100; ll_entry_t* entry1 = create_test_packet(small_size); TEST_ASSERT(entry1 != NULL, "create first small packet"); add_sent_packet(ll_entry_data(entry1), small_size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry1) == 0, "put first packet"); // Обработать packer input (пакет должен добавиться в буфер, но не отправиться) if (pair->packer->input->callback && queue_entry_count(pair->packer->input) > 0) { pair->packer->input->callback(pair->packer->input, pair->packer->input->head, pair->packer->input->callback_arg); } // Проверить, что буфер не пуст (packer накопил данные) // packer должен иметь len > 0, но мы не можем получить доступ к внутреннему состоянию. // Вместо этого проверим, что в output очереди ничего нет (пакет ещё не отправлен) int output_before = queue_entry_count(pair->packer->output); printf("After first packet: packer output queue count = %d\n", output_before); // Теперь симулируем ситуацию, когда входящая очередь пуста и вызывается callback // В реальности packer_handler вызывается при добавлении нового пакета. // Но мы можем проверить, что при следующем пакете буфер будет отправлен. // Отправим второй маленький пакет, который заставит packer отправить буфер ll_entry_t* entry2 = create_test_packet(small_size); TEST_ASSERT(entry2 != NULL, "create second small packet"); add_sent_packet(ll_entry_data(entry2), small_size); TEST_ASSERT(queue_entry_put(pair->packer->input, entry2) == 0, "put second packet"); // Обработать packer input if (pair->packer->input->callback && queue_entry_count(pair->packer->input) > 0) { pair->packer->input->callback(pair->packer->input, pair->packer->input->head, pair->packer->input->callback_arg); } // Теперь в output должна быть хотя бы одна запись (буфер отправлен) int output_after = queue_entry_count(pair->packer->output); printf("After second packet: packer output queue count = %d\n", output_after); TEST_ASSERT(output_after > output_before, "buffer flushed when new packet arrives"); // Обработать все оставшиеся очереди process_queues(pair); TEST_ASSERT(compare_packets() == 0, "both packets correctly processed"); TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no unpacker errors"); settings.max_fragment_size = original_fragment_size; return 0; } /* Тест async wait: проверка асинхронного ожидания порога в очереди */ static void test_callback(ll_queue_t* q_arg, void* arg) { (void)q_arg; int* flag = (int*)arg; *flag = 1; } static int test_async_wait(void) { printf("\n--- Test async wait: threshold waiter ---\n"); ll_queue_t* q = queue_new(test_ua); TEST_ASSERT(q != NULL, "create queue for async wait test"); int callback_called = 0; // Добавим элемент, чтобы очередь была непустой ll_entry_t* entry = queue_entry_new(10); TEST_ASSERT(entry != NULL, "create entry"); TEST_ASSERT(queue_entry_put(q, entry) == 0, "put entry"); // Регистрируем ожидание: когда очередь будет <= 0 пакетов и <= 0 байт // Условие не выполнено, поэтому коллбэк не должен вызваться сразу queue_waiter_t* waiter = queue_wait_threshold(q, 0, 0, test_callback, &callback_called); TEST_ASSERT(waiter != NULL, "waiter registered"); TEST_ASSERT(callback_called == 0, "callback not called immediately"); // Извлекаем элемент - условие должно выполниться и коллбэк вызваться ll_entry_t* retrieved = queue_entry_get(q); TEST_ASSERT(retrieved != NULL, "retrieved entry"); queue_entry_free(retrieved); // Коллбэк должен был быть вызван внутри queue_entry_get через check_waiters TEST_ASSERT(callback_called == 1, "callback called after threshold met"); // Отменяем waiter (хотя он уже должен быть удален) queue_cancel_wait(q, waiter); queue_free(q); return 0; } /* Тест 5: проверка жизненного цикла */ static int test_lifecycle(void) { printf("\n--- Test 5: lifecycle ---\n"); pkt_normalizer_pair* pair = pkt_normalizer_pair_init(test_ua); TEST_ASSERT(pair != NULL, "pair initialization"); TEST_ASSERT(pair->packer != NULL, "packer initialization"); TEST_ASSERT(pair->unpacker != NULL, "unpacker initialization"); /* Создать тестовые очереди */ ll_queue_t* test_queue = queue_new(test_ua); TEST_ASSERT(test_queue != NULL, "test queue creation"); /* Отправить один пакет */ const char* test_data = "test"; ll_entry_t* entry = queue_entry_new(strlen(test_data)); TEST_ASSERT(entry != NULL, "create test packet"); memcpy(ll_entry_data(entry), test_data, strlen(test_data)); TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put test packet"); /* Освободить всё */ pkt_normalizer_pair_deinit(pair); queue_free(test_queue); return 0; } /* Debug stress test to trace packet flow */ int main(void) { int result = 0; printf("=== Packet Normalizer Unit Test ===\n"); srand((unsigned int)time(NULL)); test_ua = uasync_create(); if (!test_ua) { fprintf(stderr, "Failed to create uasync instance\n"); return 1; } uasync_init_instance(test_ua); pkt_normalizer_pair* pair = pkt_normalizer_pair_init(test_ua); if (!pair) { fprintf(stderr, "Failed to initialize packet normalizer pair\n"); return 1; } /* Настроить цепочку обработки: packer->output -> unpacker->input -> unpacker->output */ queue_set_callback(pair->packer->output, forward_cb, pair->unpacker->input); queue_set_callback(pair->unpacker->output, receive_cb, NULL); result |= test_lifecycle(); result |= test_small_packets(pair); result |= test_medium_packet(pair); result |= test_fragmentation(pair); result |= test_mixed_packets(pair); result |= test_stress_random(pair); result |= test_edge_cases(pair); result |= test_fragmentation_verify(pair); result |= test_empty_queue_flush(pair); result |= test_async_wait(); pkt_normalizer_pair_deinit(pair); reset_test_data(); if (result == 0) { printf("\n=== All tests PASSED ===\n"); } else { printf("\n=== Some tests FAILED ===\n"); } return result; }