Mercurial
view seobeo/tests/seobeo_worker_test.c @ 279:b3b547563ec7
Add Google connector service and agent wiki
Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:22:36 -0700 |
| parents | 745fd127b2a1 |
| children |
line wrap: on
line source
#include "seobeo/seobeo_worker.h" #include <assert.h> #include <stdatomic.h> #include <stdlib.h> #include <unistd.h> typedef struct { atomic_int executed; atomic_int cleaned; atomic_int entered; atomic_int release; atomic_int cleanup_entered; atomic_int hold_cleanup; } Worker_Test_Context; typedef struct { Seobeo_Worker_Pool *p_pool; Seobeo_Worker_Result result; } Pool_Shutdown_Context; typedef struct { Seobeo_Worker_Pool *p_pool; atomic_int returned; } Pool_Wait_Context; typedef struct { Seobeo_Worker_Pool *p_pool; Seobeo_Worker_Result wait_result; Seobeo_Worker_Result shutdown_result; atomic_int cleaned; } Recursive_Cleanup_Context; static void count_task(void *p_context) { Worker_Test_Context *p_test = p_context; atomic_fetch_add(&p_test->executed, 1); } static void no_op_task(void *p_context) { (void)p_context; } static void blocking_task(void *p_context) { Worker_Test_Context *p_test = p_context; atomic_fetch_add(&p_test->executed, 1); atomic_store(&p_test->entered, 1); while (!atomic_load(&p_test->release)) usleep(1000); } static void cleanup_task(void *p_context) { Worker_Test_Context *p_test = p_context; if (atomic_load(&p_test->hold_cleanup)) { atomic_store(&p_test->cleanup_entered, 1); while (!atomic_load(&p_test->release)) usleep(1000); } atomic_fetch_add(&p_test->cleaned, 1); } static void shutdown_pool_task(void *p_context) { Pool_Shutdown_Context *p_shutdown = p_context; p_shutdown->result = Seobeo_Worker_Pool_Shutdown(p_shutdown->p_pool, FALSE); } static void wait_pool_task(void *p_context) { Pool_Wait_Context *p_wait = p_context; assert(Seobeo_Worker_Pool_Wait(p_wait->p_pool) == SEOBEO_WORKER_OK); atomic_store(&p_wait->returned, 1); } static void recursive_pool_cleanup(void *p_context) { Recursive_Cleanup_Context *p_cleanup = p_context; p_cleanup->wait_result = Seobeo_Worker_Pool_Wait(p_cleanup->p_pool); p_cleanup->shutdown_result = Seobeo_Worker_Pool_Shutdown(p_cleanup->p_pool, FALSE); Seobeo_Worker_Pool_Destroy(p_cleanup->p_pool); atomic_store(&p_cleanup->cleaned, 1); } static void wait_for_value(atomic_int *p_value, int expected) { for (int i = 0; i < 2000; i++) { if (atomic_load(p_value) == expected) return; usleep(1000); } assert(FALSE && "worker operation timed out"); } static void test_joinable_thread(void) { Worker_Test_Context context = {0}; Seobeo_Thread *p_thread = Seobeo_Thread_Start(count_task, &context, cleanup_task); assert(p_thread); assert(Seobeo_Thread_Join(p_thread) == SEOBEO_WORKER_OK); assert(atomic_load(&context.executed) == 1); assert(atomic_load(&context.cleaned) == 1); } static void test_detached_thread(void) { Worker_Test_Context context = {0}; assert(Seobeo_Thread_Start_Detached( count_task, &context, cleanup_task) == SEOBEO_WORKER_OK); wait_for_value(&context.cleaned, 1); assert(atomic_load(&context.executed) == 1); } static void test_pool_drain(void) { Worker_Test_Context context = {0}; Seobeo_Worker_Pool *p_pool = Seobeo_Worker_Pool_Create(2, 8); assert(p_pool); for (int i = 0; i < 8; i++) { assert(Seobeo_Worker_Pool_Submit( p_pool, count_task, &context, cleanup_task) == SEOBEO_WORKER_OK); } assert(Seobeo_Worker_Pool_Wait(p_pool) == SEOBEO_WORKER_OK); assert(atomic_load(&context.executed) == 8); assert(atomic_load(&context.cleaned) == 8); assert(Seobeo_Worker_Pool_Pending(p_pool) == 0); assert(Seobeo_Worker_Pool_Active(p_pool) == 0); assert(Seobeo_Worker_Pool_Shutdown(p_pool, TRUE) == SEOBEO_WORKER_OK); assert(Seobeo_Worker_Pool_Submit( p_pool, count_task, &context, cleanup_task) == SEOBEO_WORKER_STOPPED); Seobeo_Worker_Pool_Destroy(p_pool); } static void test_pool_queue_limit(void) { Worker_Test_Context context = {0}; Seobeo_Worker_Pool *p_pool = Seobeo_Worker_Pool_Create(1, 1); assert(p_pool); assert(Seobeo_Worker_Pool_Submit( p_pool, blocking_task, &context, cleanup_task) == SEOBEO_WORKER_OK); wait_for_value(&context.entered, 1); assert(Seobeo_Worker_Pool_Submit( p_pool, count_task, &context, cleanup_task) == SEOBEO_WORKER_OK); assert(Seobeo_Worker_Pool_Submit( p_pool, count_task, &context, cleanup_task) == SEOBEO_WORKER_QUEUE_FULL); atomic_store(&context.release, 1); assert(Seobeo_Worker_Pool_Wait(p_pool) == SEOBEO_WORKER_OK); assert(atomic_load(&context.executed) == 2); assert(atomic_load(&context.cleaned) == 2); Seobeo_Worker_Pool_Destroy(p_pool); } static void test_pool_cancel_queue(void) { Worker_Test_Context context = {0}; Seobeo_Worker_Pool *p_pool = Seobeo_Worker_Pool_Create(1, 4); assert(p_pool); assert(Seobeo_Worker_Pool_Submit( p_pool, blocking_task, &context, cleanup_task) == SEOBEO_WORKER_OK); wait_for_value(&context.entered, 1); assert(Seobeo_Worker_Pool_Submit( p_pool, count_task, &context, cleanup_task) == SEOBEO_WORKER_OK); Recursive_Cleanup_Context recursive = { .p_pool = p_pool, .wait_result = SEOBEO_WORKER_OK, .shutdown_result = SEOBEO_WORKER_OK, }; assert(Seobeo_Worker_Pool_Submit( p_pool, no_op_task, &recursive, recursive_pool_cleanup) == SEOBEO_WORKER_OK); atomic_store(&context.hold_cleanup, 1); Pool_Shutdown_Context shutdown = { .p_pool = p_pool, .result = SEOBEO_WORKER_THREAD_ERROR, }; Seobeo_Thread *p_shutdown = Seobeo_Thread_Start( shutdown_pool_task, &shutdown, NULL); assert(p_shutdown); wait_for_value(&context.cleanup_entered, 1); Pool_Wait_Context wait = { .p_pool = p_pool, }; Seobeo_Thread *p_wait = Seobeo_Thread_Start( wait_pool_task, &wait, NULL); assert(p_wait); usleep(20000); assert(atomic_load(&wait.returned) == 0); atomic_store(&context.release, 1); assert(Seobeo_Thread_Join(p_shutdown) == SEOBEO_WORKER_OK); assert(Seobeo_Thread_Join(p_wait) == SEOBEO_WORKER_OK); assert(shutdown.result == SEOBEO_WORKER_OK); assert(atomic_load(&context.executed) == 1); assert(atomic_load(&context.cleaned) == 2); assert(atomic_load(&recursive.cleaned) == 1); assert(recursive.wait_result == SEOBEO_WORKER_INVALID_ARGUMENT); assert(recursive.shutdown_result == SEOBEO_WORKER_INVALID_ARGUMENT); Seobeo_Worker_Pool_Destroy(p_pool); } int main(void) { assert(Seobeo_Thread_Current_Id() != 0); assert(Seobeo_Thread_Start(NULL, NULL, NULL) == NULL); assert(Seobeo_Thread_Start_Detached( NULL, NULL, NULL) == SEOBEO_WORKER_INVALID_ARGUMENT); assert(Seobeo_Worker_Pool_Create(0, 1) == NULL); assert(Seobeo_Worker_Pool_Create(1, 0) == NULL); test_joinable_thread(); test_detached_thread(); test_pool_drain(); test_pool_queue_limit(); test_pool_cancel_queue(); return 0; }