From 5156972efb8e3e8c20fda6403ee0352036e2013b Mon Sep 17 00:00:00 2001 From: theMackabu Date: Fri, 1 May 2026 13:48:51 -0700 Subject: [PATCH] add Meson build and integration test --- meson.build | 57 ++++++++++++++++++++ tests/test_integration.c | 112 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 meson.build create mode 100644 tests/test_integration.c diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..51681c7 --- /dev/null +++ b/meson.build @@ -0,0 +1,57 @@ +project('rpc', 'c', default_options: [ + 'buildtype=release', + 'optimization=3', + 'c_std=gnu23', + 'default_library=static', + 'b_lto=true', + 'b_lto_threads=8', + 'strip=true' +], version: '0.0.1') + +include = include_directories('include') + +core_sources = files( + 'src/backend/kqueue.c', + 'src/client.c', + 'src/payload.c', + 'src/protocol.c', + 'src/routes.c', + 'src/scheduler.c', + 'src/server.c', +) + +rpc_core = static_library('rpc_core', + core_sources, + include_directories: include, +) + +rpc_dep = declare_dependency( + include_directories: include, + link_with: rpc_core, +) + +executable('rpc-server', 'demos/server.c', dependencies: rpc_dep) +executable('rpc-client', 'demos/client.c', dependencies: rpc_dep) +executable('rpc-bench', 'demos/bench.c', dependencies: rpc_dep) + +test_protocol = executable('test_protocol', 'tests/test_protocol.c', + include_directories: include, + dependencies: rpc_dep, +) +test_routes = executable('test_routes', 'tests/test_routes.c', + include_directories: include, + link_with: rpc_core, +) +test_scheduler = executable('test_scheduler', 'tests/test_scheduler.c', + include_directories: include, + link_with: rpc_core, +) +test_integration = executable('test_integration', 'tests/test_integration.c', + include_directories: include, + dependencies: rpc_dep, +) + +test('protocol', test_protocol) +test('routes', test_routes) +test('scheduler', test_scheduler) +test('integration', test_integration, timeout: 10) \ No newline at end of file diff --git a/tests/test_integration.c b/tests/test_integration.c new file mode 100644 index 0000000..814d293 --- /dev/null +++ b/tests/test_integration.c @@ -0,0 +1,112 @@ +#include "rpc/client.h" +#include "rpc/server.h" + +#include +#include +#include + +static int add_handler(rpc_ctx *ctx, const rpc_value *args, size_t argc, + rpc_writer *out, void *user_data) { + (void)user_data; + if (argc != 2 || args[0].type != RPC_TYPE_I64 || args[1].type != RPC_TYPE_I64) { + return -1; + } + rpc_ctx_yield(ctx); + return rpc_writer_i64(out, args[0].as.i64 + args[1].as.i64); +} + +static void *server_thread(void *arg) { + rpc_server_run(arg); + return NULL; +} + +static void port_string(uint16_t port, char out[16]) { + char port_buf[16]; + snprintf(port_buf, sizeof(port_buf), "%u", port); + snprintf(out, 16, "%s", port_buf); +} + +typedef struct client_job { + uint16_t port; + int index; +} client_job; + +static void *client_thread(void *arg) { + client_job *job = arg; + char port[16]; + port_string(job->port, port); + + rpc_client *client = NULL; + assert(rpc_client_connect(&client, "127.0.0.1", port) == 0); + + rpc_writer payload; + rpc_writer_init(&payload); + rpc_writer_i64(&payload, job->index); + rpc_writer_i64(&payload, 10); + + rpc_value *values = NULL; + size_t count = 0; + assert(rpc_client_call(client, 7, &payload, &values, &count) == 0); + assert(count == 1); + assert(values[0].as.i64 == job->index + 10); + + rpc_values_free(values); + rpc_writer_free(&payload); + rpc_client_close(client); + return NULL; +} + +int main(void) { + rpc_server *server = NULL; + assert(rpc_server_init(&server) == 0); + assert(rpc_server_add_route(server, 7, add_handler, NULL) == 0); + assert(rpc_server_bind(server, "127.0.0.1", "0") == 0); + assert(rpc_server_listen(server) == 0); + uint16_t port = rpc_server_port(server); + assert(port != 0); + + pthread_t thread; + assert(pthread_create(&thread, NULL, server_thread, server) == 0); + + char port_buf[16]; + port_string(port, port_buf); + + rpc_client *client = NULL; + assert(rpc_client_connect(&client, "127.0.0.1", port_buf) == 0); + assert(rpc_client_ping(client) == 0); + + rpc_writer payload; + rpc_writer_init(&payload); + rpc_writer_i64(&payload, 5); + rpc_writer_i64(&payload, 6); + + rpc_value *values = NULL; + size_t count = 0; + assert(rpc_client_call(client, 7, &payload, &values, &count) == 0); + assert(count == 1 && values[0].type == RPC_TYPE_I64 && values[0].as.i64 == 11); + rpc_values_free(values); + rpc_writer_reset(&payload); + + assert(rpc_client_call(client, 999, &payload, &values, &count) != 0); + + enum { CLIENTS = 4 }; + pthread_t clients[CLIENTS]; + client_job jobs[CLIENTS]; + for (int i = 0; i < CLIENTS; ++i) { + jobs[i] = (client_job){.port = port, .index = i}; + assert(pthread_create(&clients[i], NULL, client_thread, &jobs[i]) == 0); + } + for (int i = 0; i < CLIENTS; ++i) { + assert(pthread_join(clients[i], NULL) == 0); + } + + assert(rpc_server_remove_route(server, 7) == 0); + assert(rpc_client_call(client, 7, &payload, &values, &count) != 0); + rpc_writer_free(&payload); + rpc_client_close(client); + + rpc_server_stop(server); + assert(pthread_join(thread, NULL) == 0); + rpc_server_destroy(server); + return 0; +} -- 2.51.2