comparison seobeo/tests/seobeo_sse_test.c @ 264:04fee26ecce0

add authenticated JRPG conversation platform Add reusable auth/session storage, owned conversation recovery, guest quotas, admin workflows, URL-routed conversation UI, mobile frame support, and parallel browser acceptance. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Fri, 07 Aug 2026 07:34:12 -0700
parents 1f9877b637e9
children
comparison
equal deleted inserted replaced
263:ee04e4e69fed 264:04fee26ecce0
5 #include <stdatomic.h> 5 #include <stdatomic.h>
6 #include <stdio.h> 6 #include <stdio.h>
7 #include <string.h> 7 #include <string.h>
8 #include <sys/socket.h> 8 #include <sys/socket.h>
9 #include <unistd.h> 9 #include <unistd.h>
10
11 /* Counter incremented by the detach callback. */
12 static _Atomic int g_detach_count = 0;
13 static Seobeo_SSE_Stream *g_detach_stream = NULL;
14
15 static void test_detach_cb(Seobeo_SSE_Stream *p_stream, void *ctx)
16 {
17 (void)ctx;
18 g_detach_stream = p_stream;
19 atomic_fetch_add(&g_detach_count, 1);
20 }
10 21
11 static void read_expected(int socket_fd, const char *expected) 22 static void read_expected(int socket_fd, const char *expected)
12 { 23 {
13 size_t expected_length = strlen(expected); 24 size_t expected_length = strlen(expected);
14 size_t received = 0; 25 size_t received = 0;
184 Seobeo_SSE_Release(p_managed); 195 Seobeo_SSE_Release(p_managed);
185 Seobeo_SSE_Server_Destroy(); 196 Seobeo_SSE_Server_Destroy();
186 close(sockets[0]); 197 close(sockets[0]);
187 close(sockets[1]); 198 close(sockets[1]);
188 199
200 /*
201 * Detach callback test: verify callback fires after handle detach and
202 * that the callback is called outside g_sse_mutex (no deadlock).
203 */
204 {
205 int cbs[2];
206 assert(socketpair(AF_UNIX, SOCK_STREAM, 0, cbs) == 0);
207 uint8 cb_write_buf[4096] = {0};
208 Seobeo_Handle cb_handle;
209 initialize_handle(&cb_handle, cbs[0], cb_write_buf, sizeof(cb_write_buf));
210 Seobeo_SSE_Stream *p_cb_stream = Seobeo_SSE_Server_Attach(&cb_handle, "/cb");
211 assert(p_cb_stream);
212 assert(Seobeo_SSE_Retain(p_cb_stream)); /* extra reference */
213
214 /* Register detach callback. */
215 atomic_store(&g_detach_count, 0);
216 g_detach_stream = NULL;
217 Seobeo_SSE_Set_Detach_Callback(p_cb_stream, test_detach_cb, NULL);
218
219 /* Detach: fires callback outside the mutex. */
220 Seobeo_SSE_Server_Detach_Handle(&cb_handle);
221
222 assert(atomic_load(&g_detach_count) == 1);
223 assert(g_detach_stream == p_cb_stream);
224 assert(!Seobeo_SSE_Is_Open(p_cb_stream));
225
226 /* Second detach: no stream found, callback NOT called again. */
227 Seobeo_SSE_Server_Detach_Handle(&cb_handle);
228 assert(atomic_load(&g_detach_count) == 1);
229
230 /* Clear the callback and verify it isn't called on a subsequent release. */
231 Seobeo_SSE_Set_Detach_Callback(p_cb_stream, NULL, NULL);
232 Seobeo_SSE_Release(p_cb_stream); /* release extra reference */
233 Seobeo_SSE_Server_Destroy();
234 close(cbs[0]);
235 close(cbs[1]);
236 printf(" detach callback fires once, outside mutex PASS\n");
237 }
238
189 Seobeo_Router_Init(); 239 Seobeo_Router_Init();
190 Seobeo_Router_Register_SSE("/events/:topic", route_handler); 240 Seobeo_Router_Register_SSE("/events/:topic", route_handler);
191 Seobeo_Router_Register_SSE("/events/:topic/fixed", route_handler); 241 Seobeo_Router_Register_SSE("/events/:topic/fixed", route_handler);
192 Seobeo_Router_Register_SSE_Method( 242 Seobeo_Router_Register_SSE_Method(
193 "POST", 243 "POST",
194 "/events/:topic", 244 "/events/:topic",
195 post_route_handler); 245 post_route_handler);
196 Dowa_Arena *p_arena = Dowa_Arena_Create(4096); 246 Dowa_Arena *p_arena = Dowa_Arena_Create(4096); Seobeo_Request_Entry *p_request = NULL;
197 Seobeo_Request_Entry *p_request = NULL;
198 Seobeo_SSE_Handler handler = Seobeo_Router_Find_SSE_Handler( 247 Seobeo_SSE_Handler handler = Seobeo_Router_Find_SSE_Handler(
199 "GET", 248 "GET",
200 "/events/builds", 249 "/events/builds",
201 &p_request, 250 &p_request,
202 p_arena); 251 p_arena);