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.
 
 
 
 
 
 

258 lines
7.3 KiB

// test_uasync_random.c - Test uasync instance with random timeouts
#include "u_async.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX_TIMEOUTS 1000
#define MAX_TIMEOUT_TB 10000 // 1 second in timebase units (0.1 ms)
#define CANCEL_PROBABILITY 20 // 20% chance to cancel a timeout
#define NUM_ITERATIONS 50000
typedef struct {
int id;
int fired;
int cancelled;
uasync_t* ua;
} test_context_t;
static int g_fired_count = 0;
static int g_cancelled_count = 0;
static int g_expected_fired = 0;
static void timeout_callback(void* arg) {
test_context_t* ctx = (test_context_t*)arg;
if (!ctx) return;
if (ctx->cancelled) {
printf("ERROR: Cancelled timeout %d fired!\n", ctx->id);
exit(1);
}
ctx->fired = 1;
g_fired_count++;
// Verify the timeout was removed from heap
// (we can't directly check, but we trust the implementation)
}
static void run_random_test(void) {
printf("=== Random uasync timeout test ===\n");
// Create uasync instance
uasync_t* ua = uasync_create();
if (!ua) {
printf("FAIL: uasync_create returned NULL\n");
exit(1);
}
printf("Created uasync instance\n");
// Allocate test contexts
test_context_t* contexts = malloc(MAX_TIMEOUTS * sizeof(test_context_t));
if (!contexts) {
printf("FAIL: malloc failed\n");
uasync_destroy(ua);
exit(1);
}
memset(contexts, 0, MAX_TIMEOUTS * sizeof(test_context_t));
srand(time(NULL));
// Set random timeouts
int active_timeouts = 0;
for (int i = 0; i < MAX_TIMEOUTS; i++) {
contexts[i].id = i;
contexts[i].ua = ua;
// Random timeout between 1 and MAX_TIMEOUT_TB
int timeout_tb = (rand() % MAX_TIMEOUT_TB) + 1;
void* handle = uasync_set_timeout(ua, timeout_tb, &contexts[i], timeout_callback);
if (!handle) {
printf("WARN: uasync_set_timeout failed for timeout %d\n", i);
continue;
}
// Store handle in context (we could store it, but we'll just track)
contexts[i].fired = 0;
contexts[i].cancelled = 0;
active_timeouts++;
// Randomly cancel some timeouts
if (rand() % 100 < CANCEL_PROBABILITY) {
if (uasync_cancel_timeout(ua, handle) == ERR_OK) {
contexts[i].cancelled = 1;
g_cancelled_count++;
active_timeouts--;
} else {
printf("WARN: Failed to cancel timeout %d\n", i);
}
}
}
g_expected_fired = active_timeouts;
printf("Set %d timeouts, cancelled %d, expecting %d to fire\n",
MAX_TIMEOUTS, g_cancelled_count, g_expected_fired);
// Run event loop for enough time to fire all timeouts
// Calculate maximum timeout in milliseconds plus some margin
int max_timeout_ms = (MAX_TIMEOUT_TB + 1000) / 10; // convert to ms with margin
int iterations = 0;
while (g_fired_count < g_expected_fired && iterations < NUM_ITERATIONS) {
// Poll with short timeout (10ms = 100 timebase units)
uasync_poll(ua, 100);
iterations++;
// Check if we've waited long enough
if (iterations * 10 > max_timeout_ms * 5) {
// We've waited five times the max timeout, something might be wrong
if (g_fired_count < g_expected_fired) {
printf("WARN: Only %d of %d timeouts fired after %d ms\n",
g_fired_count, g_expected_fired, iterations * 10);
break;
}
}
}
// Verify all non-cancelled timeouts fired
int failed_fires = 0;
for (int i = 0; i < MAX_TIMEOUTS; i++) {
if (!contexts[i].cancelled && !contexts[i].fired) {
failed_fires++;
if (failed_fires < 10) { // Limit output
printf("ERROR: Timeout %d didn't fire (not cancelled)\n", i);
}
}
if (contexts[i].cancelled && contexts[i].fired) {
printf("ERROR: Cancelled timeout %d fired\n", i);
failed_fires++;
}
}
if (failed_fires > 0) {
printf("FAIL: %d timeout failures\n", failed_fires);
} else {
printf("PASS: All %d expected timeouts fired correctly\n", g_fired_count);
}
// Verify that no cancelled timeouts fired (already checked above)
printf("Cancelled timeouts: %d (none should fire)\n", g_cancelled_count);
// Cleanup
free(contexts);
uasync_destroy(ua);
if (failed_fires == 0) {
printf("=== Test PASSED ===\n");
} else {
printf("=== Test FAILED ===\n");
exit(1);
}
}
static void simple_callback(void* arg) {
int* flag = (int*)arg;
*flag = 1;
}
static void free_callback(void* arg) {
free(arg);
}
static void test_instance_isolation(void) {
printf("\n=== Instance isolation test ===\n");
// Create two independent instances
uasync_t* ua1 = uasync_create();
uasync_t* ua2 = uasync_create();
if (!ua1 || !ua2) {
printf("FAIL: Failed to create instances\n");
exit(1);
}
int fired1 = 0;
int fired2 = 0;
void* timeout1 = uasync_set_timeout(ua1, 10, &fired1, simple_callback);
void* timeout2 = uasync_set_timeout(ua2, 20, &fired2, simple_callback);
if (!timeout1 || !timeout2) {
printf("FAIL: Failed to set timeouts\n");
exit(1);
}
// Run first instance - should fire timeout1 only
uasync_poll(ua1, 50); // 5ms wait
if (fired1 != 1) {
printf("FAIL: Instance 1 timeout didn't fire\n");
exit(1);
}
if (fired2 != 0) {
printf("FAIL: Instance 2 timeout fired incorrectly\n");
exit(1);
}
// Cancel timeout2
if (uasync_cancel_timeout(ua2, timeout2) != ERR_OK) {
printf("FAIL: Failed to cancel timeout2\n");
exit(1);
}
// Run second instance - nothing should fire
fired1 = 0;
uasync_poll(ua2, 50);
if (fired1 != 0) {
printf("FAIL: Instance 1 timeout fired from instance 2\n");
exit(1);
}
if (fired2 != 0) {
printf("FAIL: Cancelled timeout fired\n");
exit(1);
}
uasync_destroy(ua1);
uasync_destroy(ua2);
printf("PASS: Instance isolation works correctly\n");
}
static void test_memory_cleanup(void) {
printf("\n=== Memory cleanup test ===\n");
uasync_t* ua = uasync_create();
if (!ua) {
printf("FAIL: uasync_create failed\n");
exit(1);
}
// Set many timeouts
for (int i = 0; i < 100; i++) {
int* counter = malloc(sizeof(int));
*counter = i;
uasync_set_timeout(ua, 1000 + i, counter, free_callback);
}
// Destroy instance without waiting for timeouts
// This should free all pending timeout nodes
uasync_destroy(ua);
printf("PASS: Memory cleanup completed\n");
}
int main(void) {
printf("Starting uasync random timeout tests\n");
printf("====================================\n");
run_random_test();
test_instance_isolation();
test_memory_cleanup();
printf("\n====================================\n");
printf("All tests PASSED!\n");
return 0;
}