Mercurial
view seobeo/tests/seobeo_sse_server_test.c @ 270:358dd5950985
sync production config on every deploy
Always install the ignored repository .config into /etc/mrjunejune before promoting the new bundle.
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 07 Aug 2026 13:16:47 -0700 |
| parents | 1f9877b637e9 |
| children |
line wrap: on
line source
#include "seobeo/seobeo.h" #include <assert.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/wait.h> #include <unistd.h> static int reserve_port(void) { int socket_fd = socket(AF_INET, SOCK_STREAM, 0); assert(socket_fd >= 0); struct sockaddr_in address = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), .sin_port = 0, }; assert(bind( socket_fd, (struct sockaddr *)&address, sizeof(address)) == 0); socklen_t length = sizeof(address); assert(getsockname( socket_fd, (struct sockaddr *)&address, &length) == 0); int port = ntohs(address.sin_port); close(socket_fd); return port; } static int connect_to(int port) { int socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) return -1; struct timeval timeout = { .tv_sec = 3, }; setsockopt( socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); struct sockaddr_in address = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), .sin_port = htons((uint16)port), }; if (connect( socket_fd, (struct sockaddr *)&address, sizeof(address)) != 0) { close(socket_fd); return -1; } return socket_fd; } static void send_request( int socket_fd, const char *method, const char *path, const char *body) { char request[512]; size_t body_length = body ? strlen(body) : 0; int length = snprintf( request, sizeof(request), "%s %s HTTP/1.1\r\n" "Host: 127.0.0.1\r\n" "Content-Length: %zu\r\n" "Connection: keep-alive\r\n" "\r\n" "%s", method, path, body_length, body ? body : ""); assert(length > 0 && (size_t)length < sizeof(request)); assert(send(socket_fd, request, (size_t)length, 0) == length); } static size_t receive_until( int socket_fd, char *buffer, size_t capacity, const char *needle) { size_t used = 0; while (used + 1 < capacity) { ssize_t amount = recv( socket_fd, buffer + used, capacity - used - 1, 0); assert(amount > 0); used += (size_t)amount; buffer[used] = '\0'; if (strstr(buffer, needle)) return used; } assert(FALSE && "response exceeded test buffer"); return 0; } static pid_t start_server( const char *binary, const char *port) { pid_t pid = fork(); assert(pid >= 0); if (pid == 0) { execl(binary, binary, port, NULL); _exit(127); } int numeric_port = atoi(port); for (int attempt = 0; attempt < 100; attempt++) { int socket_fd = connect_to(numeric_port); if (socket_fd >= 0) { close(socket_fd); return pid; } usleep(20000); } kill(pid, SIGTERM); waitpid(pid, NULL, 0); assert(FALSE && "SSE test server did not start"); return -1; } int main(int argc, char **argv) { assert(argc == 2); int port = reserve_port(); char port_text[16]; snprintf(port_text, sizeof(port_text), "%d", port); pid_t server = start_server(argv[1], port_text); int event_socket = connect_to(port); assert(event_socket >= 0); send_request(event_socket, "GET", "/events", NULL); char events[4096] = {0}; receive_until( event_socket, events, sizeof(events), "data: later\n\n"); assert(strstr(events, "HTTP/1.1 200 OK\r\n")); assert(strstr(events, "Content-Type: text/event-stream\r\n")); assert(strstr(events, "data: connected\n\n")); int post_socket = connect_to(port); assert(post_socket >= 0); send_request( post_socket, "POST", "/events/builds", "deploy=release"); char post_events[4096] = {0}; receive_until( post_socket, post_events, sizeof(post_events), "data: topic=builds body=deploy=release\n\n"); assert(strstr(post_events, "HTTP/1.1 200 OK\r\n")); assert(strstr(post_events, "Content-Type: text/event-stream\r\n")); int wrong_method_socket = connect_to(port); assert(wrong_method_socket >= 0); send_request( wrong_method_socket, "PUT", "/events/builds", NULL); char wrong_method[1024] = {0}; receive_until( wrong_method_socket, wrong_method, sizeof(wrong_method), "\r\n\r\n"); assert(strstr(wrong_method, "HTTP/1.1 404 Not Found\r\n")); int health_socket = connect_to(port); assert(health_socket >= 0); send_request(health_socket, "GET", "/health", NULL); assert(shutdown(health_socket, SHUT_WR) == 0); char health[1024] = {0}; receive_until(health_socket, health, sizeof(health), "\r\n\r\nok"); assert(strstr(health, "HTTP/1.1 200 OK\r\n")); close(health_socket); close(wrong_method_socket); close(post_socket); close(event_socket); kill(server, SIGTERM); waitpid(server, NULL, 0); printf("Seobeo SSE server integration test passed\n"); return 0; }