Files
codebase-memory-mcp/tests/test_daemon_runtime.c
T
2026-07-16 19:20:46 +02:00

4012 lines
163 KiB
C

/*
* test_daemon_runtime.c — RED contract for the mandatory daemon runtime.
*
* These tests exercise a real in-process service over the authenticated IPC
* transport. A focused isolated host child also pins listener-before-background
* ordering; frontend bootstrap remains covered at its own layer.
*/
#include "test_framework.h"
#include "test_helpers.h"
#include "daemon/host.h"
#include "daemon/host_internal.h"
#include "daemon/ipc.h"
#include "daemon/runtime.h"
#include "daemon/service.h"
#include "foundation/compat.h"
#include "foundation/compat_fs.h"
#include "foundation/compat_thread.h"
#include "foundation/log.h"
#include "foundation/platform.h"
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdatomic.h>
#include <string.h>
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include "foundation/win_utf8.h"
#include <stddef.h>
#include <windows.h>
#else
#include <errno.h>
#include <fcntl.h>
#ifdef __APPLE__
#include <libproc.h>
#endif
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
enum {
RUNTIME_TEST_PATH_CAP = 1024,
RUNTIME_TEST_LOG_CAP = 4096,
RUNTIME_TEST_TIMEOUT_MS = 2000,
/* Generation-zero rendezvous layout, deliberately repeated rather than
* derived from production macros so an accidental resize fails loudly. */
RUNTIME_TEST_RENDEZVOUS_ABI = 1,
RUNTIME_TEST_RENDEZVOUS_REQUEST_SIZE = 133,
RUNTIME_TEST_RENDEZVOUS_RESPONSE_SIZE = 798,
RUNTIME_TEST_RENDEZVOUS_VERSION_OFFSET = 4,
RUNTIME_TEST_RENDEZVOUS_BUILD_OFFSET = 68,
RUNTIME_TEST_RENDEZVOUS_ACTIVE_VERSION_OFFSET = 28,
RUNTIME_TEST_RENDEZVOUS_ACTIVE_BUILD_OFFSET = 92,
RUNTIME_TEST_RENDEZVOUS_REQUESTED_VERSION_OFFSET = 157,
RUNTIME_TEST_RENDEZVOUS_REQUESTED_BUILD_OFFSET = 221,
RUNTIME_TEST_RENDEZVOUS_MESSAGE_OFFSET = 286,
/* Activation shutdown is a separate frozen first-frame envelope:
* u32 action followed byte-for-byte by the 133-byte identity above.
* Response: u32 ABI, u32 accepted, u64 clients, u64 connections. */
RUNTIME_TEST_ACTIVATION_REQUEST_SIZE = 137,
RUNTIME_TEST_ACTIVATION_RESPONSE_SIZE = 24,
RUNTIME_TEST_ACTIVATION_IDENTITY_OFFSET = 4,
RUNTIME_TEST_ACTIVATION_RESPONSE_CLIENTS_OFFSET = 8,
RUNTIME_TEST_ACTIVATION_RESPONSE_CONNECTIONS_OFFSET = 16,
};
_Static_assert(CBM_DAEMON_RUNTIME_OP_ACTIVATION_SHUTDOWN == 8 &&
CBM_DAEMON_ACTIVATION_SHUTDOWN_REQUEST_SIZE ==
RUNTIME_TEST_ACTIVATION_REQUEST_SIZE &&
CBM_DAEMON_ACTIVATION_SHUTDOWN_RESPONSE_SIZE ==
RUNTIME_TEST_ACTIVATION_RESPONSE_SIZE,
"activation shutdown frozen wire contract changed");
static const char RUNTIME_BUILD_B[] =
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
static char runtime_self_build[CBM_DAEMON_BUILD_FINGERPRINT_SIZE];
static atomic_bool runtime_conflict_log_fallback_seen;
static atomic_bool runtime_activation_shutdown_log_seen;
static void runtime_test_conflict_log_fallback_sink(const char *line) {
if (line && strstr(line, "daemon.conflict_log_append_failed")) {
atomic_store_explicit(&runtime_conflict_log_fallback_seen, true,
memory_order_release);
}
}
static void runtime_test_activation_shutdown_sink(const char *line) {
if (line && strstr(line, "daemon.activation_shutdown") &&
strstr(line, "requester_pid") && strstr(line, "requester_build") &&
strstr(line, "action") && strstr(line, "active_clients") &&
strstr(line, "active_connections")) {
atomic_store_explicit(&runtime_activation_shutdown_log_seen, true,
memory_order_release);
}
}
typedef struct {
char parent[RUNTIME_TEST_PATH_CAP];
char runtime_dir[RUNTIME_TEST_PATH_CAP];
char key[CBM_DAEMON_KEY_SIZE];
char log_path[RUNTIME_TEST_PATH_CAP];
char rotated_log_path[RUNTIME_TEST_PATH_CAP];
char lock_log_path[RUNTIME_TEST_PATH_CAP];
cbm_daemon_ipc_endpoint_t *endpoint;
cbm_daemon_runtime_service_t *service;
} runtime_test_fixture_t;
typedef struct {
atomic_int opened;
atomic_int requests;
atomic_int request_cancels;
atomic_int cancelled;
atomic_int closed;
atomic_bool block_first_request;
atomic_bool first_request_started;
atomic_bool ignore_first_request_cancel;
atomic_bool release_first_request;
atomic_bool block_second_open;
atomic_bool second_open_started;
atomic_bool release_second_open;
} runtime_application_context_t;
typedef struct {
runtime_application_context_t *context;
atomic_bool cancel_requested;
cbm_daemon_client_id_t client_id;
uint64_t authenticated_process_id;
} runtime_application_session_t;
typedef struct {
cbm_daemon_runtime_client_t *client;
const uint8_t *request;
uint32_t request_length;
cbm_daemon_runtime_application_token_t request_token;
bool tagged;
atomic_bool *completed;
cbm_daemon_runtime_application_status_t status;
uint8_t *response;
uint32_t response_length;
} runtime_application_client_call_t;
typedef struct {
const cbm_daemon_ipc_endpoint_t *endpoint;
cbm_daemon_build_identity_t identity;
cbm_daemon_runtime_connect_result_t result;
cbm_daemon_runtime_client_t *client;
atomic_bool completed;
} runtime_application_connect_call_t;
static cbm_daemon_build_identity_t runtime_test_identity(const char *version,
const char *build) {
cbm_daemon_build_identity_t identity = {
.semantic_version = version,
.build_fingerprint = build,
.protocol_abi = 3,
.store_abi = 11,
.feature_abi = 7,
};
return identity;
}
static uint64_t runtime_test_process_id(void) {
#ifdef _WIN32
return (uint64_t)GetCurrentProcessId();
#else
return (uint64_t)getpid();
#endif
}
static const char *runtime_test_self_build(void) {
if (runtime_self_build[0] == '\0') {
(void)cbm_daemon_runtime_process_build_fingerprint(
runtime_test_process_id(), runtime_self_build);
}
return runtime_self_build;
}
static bool runtime_test_is_fingerprint(const char *value) {
if (!value || strlen(value) != CBM_DAEMON_BUILD_FINGERPRINT_SIZE - 1) {
return false;
}
for (size_t i = 0; i < CBM_DAEMON_BUILD_FINGERPRINT_SIZE - 1; i++) {
char ch = value[i];
if (!((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f'))) {
return false;
}
}
return true;
}
static bool runtime_test_copy_path(char out[RUNTIME_TEST_PATH_CAP], const char *path) {
if (!path) {
out[0] = '\0';
return false;
}
int written = snprintf(out, RUNTIME_TEST_PATH_CAP, "%s", path);
return written >= 0 && written < RUNTIME_TEST_PATH_CAP;
}
#ifdef _WIN32
enum {
RUNTIME_TEST_FILE_RENAME_INFO_EX = 22,
RUNTIME_TEST_FILE_RENAME_REPLACE_IF_EXISTS = 0x00000001,
RUNTIME_TEST_FILE_RENAME_POSIX_SEMANTICS = 0x00000002,
};
typedef struct {
DWORD flags;
HANDLE root_directory;
DWORD file_name_length;
wchar_t file_name[1];
} runtime_test_windows_rename_info_t;
static bool runtime_test_windows_copy_self(const char *destination) {
wchar_t source[32768];
DWORD source_length = GetModuleFileNameW(
NULL, source, (DWORD)(sizeof(source) / sizeof(source[0])));
wchar_t *destination_wide = cbm_utf8_to_wide(destination);
bool copied = source_length > 0 &&
source_length <
(DWORD)(sizeof(source) / sizeof(source[0])) &&
destination_wide &&
CopyFileW(source, destination_wide, TRUE) != 0;
free(destination_wide);
return copied;
}
static bool runtime_test_windows_posix_replace(const char *source,
const char *destination) {
wchar_t *source_wide = cbm_utf8_to_wide(source);
wchar_t *destination_wide = cbm_utf8_to_wide(destination);
size_t destination_length =
destination_wide ? wcslen(destination_wide) : 0;
size_t destination_bytes = destination_length * sizeof(wchar_t);
size_t information_size =
offsetof(runtime_test_windows_rename_info_t, file_name) +
destination_bytes + sizeof(wchar_t);
bool sizes_ok = destination_length > 0 &&
destination_bytes <= MAXDWORD &&
information_size <= MAXDWORD;
runtime_test_windows_rename_info_t *information =
sizes_ok ? calloc(1, information_size) : NULL;
if (information) {
information->flags =
RUNTIME_TEST_FILE_RENAME_REPLACE_IF_EXISTS |
RUNTIME_TEST_FILE_RENAME_POSIX_SEMANTICS;
information->file_name_length = (DWORD)destination_bytes;
memcpy(information->file_name, destination_wide,
destination_bytes + sizeof(wchar_t));
}
HANDLE source_file =
source_wide && information
? CreateFileW(source_wide, DELETE | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_OPEN_REPARSE_POINT,
NULL)
: INVALID_HANDLE_VALUE;
bool replaced =
source_file != INVALID_HANDLE_VALUE &&
SetFileInformationByHandle(
source_file,
(FILE_INFO_BY_HANDLE_CLASS)RUNTIME_TEST_FILE_RENAME_INFO_EX,
information, (DWORD)information_size) != 0;
if (source_file != INVALID_HANDLE_VALUE && !CloseHandle(source_file)) {
replaced = false;
}
free(information);
free(destination_wide);
free(source_wide);
return replaced;
}
static bool runtime_test_windows_spawn_image_holder(
const char *image_path, const char *ready_event,
PROCESS_INFORMATION *process_out) {
if (!image_path || !ready_event || !process_out) {
return false;
}
memset(process_out, 0, sizeof(*process_out));
char command_line[RUNTIME_TEST_PATH_CAP * 2];
int written = snprintf(command_line, sizeof(command_line),
"\"%s\" __cbm_runtime_image_holder \"%s\"",
image_path, ready_event);
wchar_t *application = cbm_utf8_to_wide(image_path);
wchar_t *command = written > 0 && written < (int)sizeof(command_line)
? cbm_utf8_to_wide(command_line)
: NULL;
STARTUPINFOW startup;
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
bool created = application && command &&
CreateProcessW(application, command, NULL, NULL, FALSE,
CREATE_NO_WINDOW, NULL, NULL, &startup,
process_out) != 0;
free(command);
free(application);
if (created) {
(void)CloseHandle(process_out->hThread);
process_out->hThread = NULL;
}
return created;
}
#endif
#if defined(__APPLE__) || defined(__linux__)
static bool runtime_test_copy_executable(const char *source,
const char *destination) {
int source_fd = open(source, O_RDONLY | O_CLOEXEC);
int destination_fd = source_fd >= 0
? open(destination,
O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC,
0700)
: -1;
unsigned char buffer[64 * 1024];
bool ok = source_fd >= 0 && destination_fd >= 0;
while (ok) {
ssize_t count = read(source_fd, buffer, sizeof(buffer));
if (count == 0) {
break;
}
if (count < 0) {
if (errno == EINTR) {
continue;
}
ok = false;
break;
}
size_t written = 0;
while (written < (size_t)count) {
ssize_t chunk = write(destination_fd, buffer + written,
(size_t)count - written);
if (chunk > 0) {
written += (size_t)chunk;
} else if (chunk < 0 && errno == EINTR) {
continue;
} else {
ok = false;
break;
}
}
}
if (destination_fd >= 0 && fchmod(destination_fd, 0700) != 0) {
ok = false;
}
if (destination_fd >= 0 && close(destination_fd) != 0) {
ok = false;
}
if (source_fd >= 0 && close(source_fd) != 0) {
ok = false;
}
if (!ok) {
(void)unlink(destination);
}
return ok;
}
static pid_t runtime_test_spawn_blocked_executable(const char *path,
int *release_fd_out) {
int ready[2] = {-1, -1};
int input[2] = {-1, -1};
if (!path || !release_fd_out || pipe(ready) != 0 || pipe(input) != 0) {
if (ready[0] >= 0) {
(void)close(ready[0]);
(void)close(ready[1]);
}
if (input[0] >= 0) {
(void)close(input[0]);
(void)close(input[1]);
}
return -1;
}
int ready_flags = fcntl(ready[1], F_GETFD);
if (ready_flags < 0 ||
fcntl(ready[1], F_SETFD, ready_flags | FD_CLOEXEC) != 0) {
(void)close(ready[0]);
(void)close(ready[1]);
(void)close(input[0]);
(void)close(input[1]);
return -1;
}
pid_t child = fork();
if (child == 0) {
(void)close(ready[0]);
(void)close(input[1]);
if (dup2(input[0], STDIN_FILENO) < 0) {
_exit(126);
}
if (input[0] != STDIN_FILENO) {
(void)close(input[0]);
}
execl(path, path, (char *)NULL);
const char failed = 'x';
(void)write(ready[1], &failed, 1);
_exit(127);
}
(void)close(ready[1]);
(void)close(input[0]);
char unexpected = '\0';
ssize_t ready_count;
do {
ready_count = read(ready[0], &unexpected, 1);
} while (ready_count < 0 && errno == EINTR);
(void)close(ready[0]);
int status = 0;
bool running = child > 0 && ready_count == 0 &&
waitpid(child, &status, WNOHANG) == 0;
if (!running) {
(void)close(input[1]);
if (child > 0) {
(void)kill(child, SIGKILL);
while (waitpid(child, &status, 0) < 0 && errno == EINTR) {
}
}
return -1;
}
*release_fd_out = input[1];
return child;
}
static void runtime_test_stop_blocked_executable(pid_t child, int release_fd) {
if (release_fd >= 0) {
(void)close(release_fd);
}
if (child <= 0) {
return;
}
(void)kill(child, SIGTERM);
int status = 0;
while (waitpid(child, &status, 0) < 0 && errno == EINTR) {
}
}
#endif
#if defined(__APPLE__) || defined(__linux__)
static bool runtime_test_self_image_path(
char source[RUNTIME_TEST_PATH_CAP]) {
#ifdef __APPLE__
int length = proc_pidpath(getpid(), source, RUNTIME_TEST_PATH_CAP);
bool resolved = length > 0 && length < RUNTIME_TEST_PATH_CAP;
if (resolved) {
source[length] = '\0';
}
#else
ssize_t length =
readlink("/proc/self/exe", source, RUNTIME_TEST_PATH_CAP - 1);
bool resolved = length > 0 &&
length < (ssize_t)RUNTIME_TEST_PATH_CAP - 1;
if (resolved) {
source[length] = '\0';
}
#endif
return resolved;
}
#endif
static bool runtime_test_copy_self_image(const char *destination) {
#ifdef _WIN32
return runtime_test_windows_copy_self(destination);
#elif defined(__APPLE__) || defined(__linux__)
char source[RUNTIME_TEST_PATH_CAP];
return runtime_test_self_image_path(source) &&
runtime_test_copy_executable(source, destination);
#else
(void)destination;
return false;
#endif
}
#if defined(_WIN32) || defined(__linux__)
static bool runtime_test_append_image_marker(const char *path) {
FILE *file = cbm_fopen(path, "ab");
bool written = file && fputc('\n', file) != EOF;
if (file) {
written = fclose(file) == 0 && written;
}
return written;
}
#endif
#ifdef __APPLE__
static bool runtime_test_mac_ad_hoc_sign(const char *path) {
if (!path) {
return false;
}
pid_t child = fork();
if (child == 0) {
execl("/usr/bin/codesign", "codesign", "--force", "--sign", "-",
"--timestamp=none", "--identifier",
"org.deusdata.cbm.foreign-test", path, (char *)NULL);
_exit(127);
}
int status = 0;
pid_t waited;
do {
waited = child > 0 ? waitpid(child, &status, 0) : -1;
} while (waited < 0 && errno == EINTR);
return waited == child && WIFEXITED(status) && WEXITSTATUS(status) == 0;
}
#endif
static bool runtime_test_run_hello_image(
const char *image_path, const runtime_test_fixture_t *fixture,
const cbm_daemon_build_identity_t *identity, int *exit_code_out) {
if (!image_path || !fixture || !identity || !identity->semantic_version ||
!identity->build_fingerprint || !exit_code_out) {
return false;
}
*exit_code_out = -1;
#ifdef _WIN32
char command_line[RUNTIME_TEST_PATH_CAP * 3];
int written = snprintf(
command_line, sizeof(command_line),
"\"%s\" __cbm_runtime_hello_client \"%s\" %s %s %s", image_path,
fixture->parent, fixture->key, identity->semantic_version,
identity->build_fingerprint);
wchar_t *application = cbm_utf8_to_wide(image_path);
wchar_t *command = written > 0 && written < (int)sizeof(command_line)
? cbm_utf8_to_wide(command_line)
: NULL;
STARTUPINFOW startup;
PROCESS_INFORMATION process;
memset(&startup, 0, sizeof(startup));
memset(&process, 0, sizeof(process));
startup.cb = sizeof(startup);
bool started = application && command &&
CreateProcessW(application, command, NULL, NULL, FALSE,
CREATE_NO_WINDOW, NULL, NULL, &startup,
&process) != 0;
free(command);
free(application);
bool waited = started &&
WaitForSingleObject(process.hProcess, 10000) == WAIT_OBJECT_0;
DWORD exit_code = 0;
bool read = waited && GetExitCodeProcess(process.hProcess, &exit_code) != 0;
if (started) {
(void)CloseHandle(process.hThread);
(void)CloseHandle(process.hProcess);
}
if (read && exit_code <= INT_MAX) {
*exit_code_out = (int)exit_code;
}
return read && exit_code <= INT_MAX;
#elif defined(__APPLE__) || defined(__linux__)
pid_t child = fork();
if (child == 0) {
execl(image_path, image_path, "__cbm_runtime_hello_client",
fixture->parent, fixture->key, identity->semantic_version,
identity->build_fingerprint, (char *)NULL);
_exit(127);
}
int status = 0;
pid_t waited;
do {
waited = child > 0 ? waitpid(child, &status, 0) : -1;
} while (waited < 0 && errno == EINTR);
if (waited != child || !WIFEXITED(status)) {
return false;
}
*exit_code_out = WEXITSTATUS(status);
return true;
#else
(void)image_path;
(void)fixture;
(void)identity;
return false;
#endif
}
static bool runtime_test_run_activation_image(
const char *image_path, const runtime_test_fixture_t *fixture,
const cbm_daemon_build_identity_t *identity,
cbm_daemon_runtime_activation_action_t action, int *exit_code_out) {
if (!image_path || !fixture || !identity || !identity->semantic_version ||
!identity->build_fingerprint || !exit_code_out) {
return false;
}
*exit_code_out = -1;
#ifdef _WIN32
char command_line[RUNTIME_TEST_PATH_CAP * 3];
int written = snprintf(
command_line, sizeof(command_line),
"\"%s\" __cbm_runtime_activation_client \"%s\" %s %s %s %u",
image_path, fixture->parent, fixture->key,
identity->semantic_version, identity->build_fingerprint,
(unsigned int)action);
wchar_t *application = cbm_utf8_to_wide(image_path);
wchar_t *command = written > 0 && written < (int)sizeof(command_line)
? cbm_utf8_to_wide(command_line)
: NULL;
STARTUPINFOW startup;
PROCESS_INFORMATION process;
memset(&startup, 0, sizeof(startup));
memset(&process, 0, sizeof(process));
startup.cb = sizeof(startup);
bool started = application && command &&
CreateProcessW(application, command, NULL, NULL, FALSE,
CREATE_NO_WINDOW, NULL, NULL, &startup,
&process) != 0;
free(command);
free(application);
bool waited = started &&
WaitForSingleObject(process.hProcess, 10000) ==
WAIT_OBJECT_0;
if (started && !waited) {
(void)TerminateProcess(process.hProcess, 30);
(void)WaitForSingleObject(process.hProcess, 5000);
}
DWORD exit_code = 0;
bool read = waited &&
GetExitCodeProcess(process.hProcess, &exit_code) != 0;
if (started) {
(void)CloseHandle(process.hThread);
(void)CloseHandle(process.hProcess);
}
if (read && exit_code <= INT_MAX) {
*exit_code_out = (int)exit_code;
}
return read && exit_code <= INT_MAX;
#elif defined(__APPLE__) || defined(__linux__)
char action_text[16];
int action_written = snprintf(action_text, sizeof(action_text), "%u",
(unsigned int)action);
pid_t child = action_written > 0 && action_written < (int)sizeof(action_text)
? fork()
: -1;
if (child == 0) {
(void)alarm(10);
execl(image_path, image_path, "__cbm_runtime_activation_client",
fixture->parent, fixture->key, identity->semantic_version,
identity->build_fingerprint, action_text, (char *)NULL);
_exit(127);
}
int status = 0;
pid_t waited;
do {
waited = child > 0 ? waitpid(child, &status, 0) : -1;
} while (waited < 0 && errno == EINTR);
if (waited != child || !WIFEXITED(status)) {
return false;
}
*exit_code_out = WEXITSTATUS(status);
return true;
#else
(void)image_path;
(void)fixture;
(void)identity;
(void)action;
return false;
#endif
}
#ifdef __APPLE__
static bool runtime_test_run_mapped_hello_image(
const char *image_path, const char *mapped_image_path,
const runtime_test_fixture_t *fixture,
const cbm_daemon_build_identity_t *identity, int *exit_code_out) {
if (!image_path || !mapped_image_path || !fixture || !identity ||
!identity->semantic_version || !identity->build_fingerprint ||
!exit_code_out) {
return false;
}
*exit_code_out = -1;
pid_t child = fork();
if (child == 0) {
execl(image_path, image_path, "__cbm_runtime_mapped_hello_client",
mapped_image_path, fixture->parent, fixture->key,
identity->semantic_version, identity->build_fingerprint,
(char *)NULL);
_exit(127);
}
int status = 0;
pid_t waited;
do {
waited = child > 0 ? waitpid(child, &status, 0) : -1;
} while (waited < 0 && errno == EINTR);
if (waited != child || !WIFEXITED(status)) {
return false;
}
*exit_code_out = WEXITSTATUS(status);
return true;
}
#endif
static cbm_daemon_runtime_application_session_t *runtime_application_session_open(
void *opaque, cbm_daemon_client_id_t client_id,
uint64_t authenticated_process_id) {
runtime_application_context_t *context = opaque;
runtime_application_session_t *session = calloc(1, sizeof(*session));
if (!context || !session || client_id == CBM_DAEMON_CLIENT_ID_INVALID ||
authenticated_process_id == 0) {
free(session);
return NULL;
}
session->context = context;
session->client_id = client_id;
session->authenticated_process_id = authenticated_process_id;
atomic_init(&session->cancel_requested, false);
int open_index = atomic_fetch_add_explicit(&context->opened, 1,
memory_order_relaxed);
if (open_index == 1 &&
atomic_load_explicit(&context->block_second_open,
memory_order_acquire)) {
atomic_store_explicit(&context->second_open_started, true,
memory_order_release);
while (!atomic_load_explicit(&context->release_second_open,
memory_order_acquire)) {
struct timespec pause = {.tv_sec = 0, .tv_nsec = 1000000};
(void)cbm_nanosleep(&pause, NULL);
}
}
return (cbm_daemon_runtime_application_session_t *)session;
}
static cbm_daemon_runtime_application_status_t runtime_application_request(
void *opaque, cbm_daemon_runtime_application_session_t *opaque_session,
cbm_daemon_runtime_application_token_t request_token,
const uint8_t *request, uint32_t request_length, uint8_t **response_out,
uint32_t *response_length_out) {
(void)request_token;
runtime_application_context_t *context = opaque;
runtime_application_session_t *session =
(runtime_application_session_t *)opaque_session;
if (!context || !session || session->context != context || !response_out ||
!response_length_out || (request_length > 0 && !request)) {
return CBM_DAEMON_RUNTIME_APPLICATION_HANDLER_ERROR;
}
*response_out = NULL;
*response_length_out = 0;
int request_index =
atomic_fetch_add_explicit(&context->requests, 1, memory_order_relaxed);
if (request_index == 0 &&
atomic_load_explicit(&context->block_first_request,
memory_order_acquire)) {
atomic_store_explicit(&context->first_request_started, true,
memory_order_release);
bool ignore_cancel = atomic_load_explicit(
&context->ignore_first_request_cancel, memory_order_acquire);
while (!(ignore_cancel
? atomic_load_explicit(&context->release_first_request,
memory_order_acquire)
: atomic_load_explicit(&session->cancel_requested,
memory_order_acquire))) {
struct timespec pause = {.tv_sec = 0, .tv_nsec = 1000000};
(void)cbm_nanosleep(&pause, NULL);
}
return CBM_DAEMON_RUNTIME_APPLICATION_CANCELLED;
}
if (request_length == 0) {
return CBM_DAEMON_RUNTIME_APPLICATION_OK;
}
uint8_t *response = malloc(request_length);
if (!response) {
return CBM_DAEMON_RUNTIME_APPLICATION_HANDLER_ERROR;
}
memcpy(response, request, request_length);
*response_out = response;
*response_length_out = request_length;
return CBM_DAEMON_RUNTIME_APPLICATION_OK;
}
static void *runtime_application_client_request_thread(void *opaque) {
runtime_application_client_call_t *call = opaque;
call->status = call->tagged
? cbm_daemon_runtime_client_application_request_tagged(
call->client, call->request_token, call->request,
call->request_length, &call->response,
&call->response_length,
RUNTIME_TEST_TIMEOUT_MS)
: cbm_daemon_runtime_client_application_request(
call->client, call->request,
call->request_length, &call->response,
&call->response_length,
RUNTIME_TEST_TIMEOUT_MS);
if (call->completed) {
/* This must remain the helper's final access to call/client state. A
* failed OS join can then fall back to this lifetime sentinel without
* racing stack teardown or client cleanup. */
atomic_store_explicit(call->completed, true, memory_order_release);
}
return NULL;
}
static void *runtime_application_client_connect_thread(void *opaque) {
runtime_application_connect_call_t *call = opaque;
call->client = cbm_daemon_runtime_client_connect(
call->endpoint, &call->identity, RUNTIME_TEST_TIMEOUT_MS,
&call->result);
atomic_store_explicit(&call->completed, true, memory_order_release);
return NULL;
}
static void runtime_application_request_cancel(
void *opaque, cbm_daemon_runtime_application_session_t *opaque_session,
cbm_daemon_runtime_application_token_t request_token) {
(void)request_token;
runtime_application_context_t *context = opaque;
runtime_application_session_t *session =
(runtime_application_session_t *)opaque_session;
if (!context || !session || session->context != context) {
return;
}
atomic_store_explicit(&session->cancel_requested, true,
memory_order_release);
(void)atomic_fetch_add_explicit(&context->request_cancels, 1,
memory_order_relaxed);
}
static void runtime_application_session_cancel(
void *opaque, cbm_daemon_runtime_application_session_t *opaque_session) {
runtime_application_context_t *context = opaque;
runtime_application_session_t *session =
(runtime_application_session_t *)opaque_session;
if (!context || !session || session->context != context) {
return;
}
atomic_store_explicit(&session->cancel_requested, true,
memory_order_release);
(void)atomic_fetch_add_explicit(&context->cancelled, 1,
memory_order_relaxed);
}
static void runtime_application_session_close(
void *opaque, cbm_daemon_runtime_application_session_t *opaque_session) {
runtime_application_context_t *context = opaque;
runtime_application_session_t *session =
(runtime_application_session_t *)opaque_session;
if (!context || !session || session->context != context) {
return;
}
(void)atomic_fetch_add_explicit(&context->closed, 1,
memory_order_relaxed);
free(session);
}
static cbm_daemon_runtime_application_callbacks_t runtime_application_callbacks(
runtime_application_context_t *context) {
cbm_daemon_runtime_application_callbacks_t callbacks = {
.context = context,
.session_open = runtime_application_session_open,
.request = runtime_application_request,
.request_cancel = runtime_application_request_cancel,
.session_cancel = runtime_application_session_cancel,
.session_close = runtime_application_session_close,
};
return callbacks;
}
static void runtime_application_context_init(runtime_application_context_t *context,
bool block_first_request) {
memset(context, 0, sizeof(*context));
atomic_init(&context->opened, 0);
atomic_init(&context->requests, 0);
atomic_init(&context->request_cancels, 0);
atomic_init(&context->cancelled, 0);
atomic_init(&context->closed, 0);
atomic_init(&context->block_first_request, block_first_request);
atomic_init(&context->first_request_started, false);
atomic_init(&context->ignore_first_request_cancel, false);
atomic_init(&context->release_first_request, false);
atomic_init(&context->block_second_open, false);
atomic_init(&context->second_open_started, false);
atomic_init(&context->release_second_open, false);
}
static bool runtime_test_wait_atomic_bool(atomic_bool *value,
uint32_t timeout_ms) {
uint64_t deadline = cbm_now_ms() + (uint64_t)timeout_ms;
while (!atomic_load_explicit(value, memory_order_acquire)) {
if (cbm_now_ms() >= deadline) {
return false;
}
struct timespec pause = {.tv_sec = 0, .tv_nsec = 1000000};
(void)cbm_nanosleep(&pause, NULL);
}
return true;
}
static bool runtime_test_wait_atomic_int(atomic_int *value, int expected,
uint32_t timeout_ms) {
uint64_t deadline = cbm_now_ms() + (uint64_t)timeout_ms;
while (atomic_load_explicit(value, memory_order_acquire) != expected) {
if (cbm_now_ms() >= deadline) {
return false;
}
struct timespec pause = {.tv_sec = 0, .tv_nsec = 1000000};
(void)cbm_nanosleep(&pause, NULL);
}
return true;
}
static void runtime_test_put_u32(uint8_t out[4], uint32_t value) {
out[0] = (uint8_t)(value >> 24);
out[1] = (uint8_t)(value >> 16);
out[2] = (uint8_t)(value >> 8);
out[3] = (uint8_t)value;
}
static uint32_t runtime_test_get_u32(const uint8_t in[4]) {
return ((uint32_t)in[0] << 24) | ((uint32_t)in[1] << 16) |
((uint32_t)in[2] << 8) | (uint32_t)in[3];
}
static void runtime_test_put_u64(uint8_t out[8], uint64_t value) {
for (size_t index = 0; index < 8; index++) {
out[index] = (uint8_t)(value >> (56U - index * 8U));
}
}
static uint64_t runtime_test_get_u64(const uint8_t in[8]) {
uint64_t value = 0;
for (size_t index = 0; index < 8; index++) {
value = (value << 8U) | in[index];
}
return value;
}
static bool runtime_test_raw_activation_exchange(
const cbm_daemon_ipc_endpoint_t *endpoint, const uint8_t *request,
uint32_t request_length,
cbm_daemon_runtime_activation_result_t *result_out) {
if (result_out) {
memset(result_out, 0, sizeof(*result_out));
}
if (!endpoint || !request || !result_out) {
return false;
}
cbm_daemon_ipc_connection_t *connection =
cbm_daemon_ipc_connect(endpoint, RUNTIME_TEST_TIMEOUT_MS);
bool sent = connection && cbm_daemon_ipc_send_frame(
connection, CBM_DAEMON_FRAME_REQUEST,
CBM_DAEMON_RUNTIME_OP_ACTIVATION_SHUTDOWN,
request, request_length);
cbm_daemon_frame_t frame = {0};
uint8_t *response = NULL;
int received = sent ? cbm_daemon_ipc_receive_frame(
connection, RUNTIME_TEST_TIMEOUT_MS, &frame,
&response)
: 0;
uint32_t status = received == 1 && response
? runtime_test_get_u32(response + 4)
: UINT32_MAX;
bool valid = received == 1 &&
frame.type == CBM_DAEMON_FRAME_RESPONSE &&
frame.flags == CBM_DAEMON_RUNTIME_OP_ACTIVATION_SHUTDOWN &&
frame.length == RUNTIME_TEST_ACTIVATION_RESPONSE_SIZE &&
response &&
runtime_test_get_u32(response) ==
RUNTIME_TEST_RENDEZVOUS_ABI &&
status <= 1U;
if (valid) {
result_out->accepted = status == 1U;
result_out->active_clients = runtime_test_get_u64(
response + RUNTIME_TEST_ACTIVATION_RESPONSE_CLIENTS_OFFSET);
result_out->active_connections = runtime_test_get_u64(
response + RUNTIME_TEST_ACTIVATION_RESPONSE_CONNECTIONS_OFFSET);
}
free(response);
cbm_daemon_ipc_connection_close(connection);
return valid;
}
static bool runtime_test_activation_request_encode(
uint8_t out[RUNTIME_TEST_ACTIVATION_REQUEST_SIZE],
cbm_daemon_runtime_activation_action_t action,
const cbm_daemon_build_identity_t *identity) {
if (!out || !identity) {
return false;
}
memset(out, 0, RUNTIME_TEST_ACTIVATION_REQUEST_SIZE);
runtime_test_put_u32(out, (uint32_t)action);
return cbm_daemon_runtime_hello_request_encode(
out + RUNTIME_TEST_ACTIVATION_IDENTITY_OFFSET, identity);
}
static bool runtime_test_fixed_string_equals(const uint8_t *wire,
size_t capacity,
const char *expected) {
if (!wire || !expected) {
return false;
}
size_t length = strlen(expected);
if (length >= capacity || memcmp(wire, expected, length) != 0 ||
wire[length] != 0) {
return false;
}
for (size_t i = length + 1; i < capacity; i++) {
if (wire[i] != 0) {
return false;
}
}
return true;
}
static cbm_daemon_ipc_connection_t *runtime_test_raw_client_connect(
const cbm_daemon_ipc_endpoint_t *endpoint,
const cbm_daemon_build_identity_t *identity) {
uint8_t hello[CBM_DAEMON_RENDEZVOUS_REQUEST_SIZE];
if (!cbm_daemon_runtime_hello_request_encode(hello, identity)) {
return NULL;
}
cbm_daemon_ipc_connection_t *connection =
cbm_daemon_ipc_connect(endpoint, RUNTIME_TEST_TIMEOUT_MS);
if (!connection ||
!cbm_daemon_ipc_send_frame(connection, CBM_DAEMON_FRAME_REQUEST,
CBM_DAEMON_RUNTIME_OP_HELLO, hello,
(uint32_t)sizeof(hello))) {
cbm_daemon_ipc_connection_close(connection);
return NULL;
}
cbm_daemon_frame_t frame = {0};
uint8_t *payload = NULL;
int received = cbm_daemon_ipc_receive_frame(connection,
RUNTIME_TEST_TIMEOUT_MS,
&frame, &payload);
bool accepted = received == 1 && frame.type == CBM_DAEMON_FRAME_RESPONSE &&
frame.flags == CBM_DAEMON_RUNTIME_OP_HELLO &&
frame.length > 0;
free(payload);
if (!accepted) {
cbm_daemon_ipc_connection_close(connection);
return NULL;
}
return connection;
}
static bool runtime_test_raw_application_send_token(
cbm_daemon_ipc_connection_t *connection, uint64_t request_token,
const void *payload, uint32_t payload_length, uint32_t declared_length) {
uint64_t wire_length = 12ULL + payload_length;
if (!connection || request_token == 0 || wire_length > UINT32_MAX ||
(payload_length > 0 && !payload)) {
return false;
}
uint8_t *wire = malloc((size_t)wire_length);
if (!wire) {
return false;
}
runtime_test_put_u64(wire, request_token);
runtime_test_put_u32(wire + 8, declared_length);
if (payload_length > 0) {
memcpy(wire + 12, payload, payload_length);
}
bool sent = cbm_daemon_ipc_send_frame(
connection, CBM_DAEMON_FRAME_REQUEST,
CBM_DAEMON_RUNTIME_OP_APPLICATION_REQUEST, wire,
(uint32_t)wire_length);
free(wire);
return sent;
}
static bool runtime_test_raw_application_send(
cbm_daemon_ipc_connection_t *connection, const void *payload,
uint32_t payload_length, uint32_t declared_length) {
static atomic_uint_fast64_t next_token = ATOMIC_VAR_INIT(1);
uint64_t request_token = atomic_fetch_add_explicit(
&next_token, 1, memory_order_relaxed);
return runtime_test_raw_application_send_token(
connection, request_token, payload, payload_length, declared_length);
}
static bool runtime_test_raw_application_cancel(
cbm_daemon_ipc_connection_t *connection, uint64_t request_token) {
uint8_t wire[8];
if (!connection || request_token == 0) {
return false;
}
runtime_test_put_u64(wire, request_token);
return cbm_daemon_ipc_send_frame(
connection, CBM_DAEMON_FRAME_REQUEST,
CBM_DAEMON_RUNTIME_OP_APPLICATION_CANCEL, wire,
(uint32_t)sizeof(wire));
}
static bool runtime_test_raw_application_receive_status_token(
cbm_daemon_ipc_connection_t *connection,
uint64_t expected_token,
cbm_daemon_runtime_application_status_t expected_status) {
cbm_daemon_frame_t frame = {0};
uint8_t *payload = NULL;
int received = cbm_daemon_ipc_receive_frame(connection,
RUNTIME_TEST_TIMEOUT_MS,
&frame, &payload);
bool valid = received == 1 && frame.type == CBM_DAEMON_FRAME_RESPONSE &&
frame.flags == CBM_DAEMON_RUNTIME_OP_APPLICATION_REQUEST &&
frame.length >= 16 && payload &&
runtime_test_get_u64(payload) == expected_token &&
runtime_test_get_u32(payload + 8) ==
(uint32_t)expected_status &&
runtime_test_get_u32(payload + 12) == frame.length - 16;
free(payload);
return valid;
}
static bool runtime_test_raw_application_receive_status(
cbm_daemon_ipc_connection_t *connection,
cbm_daemon_runtime_application_status_t expected_status) {
cbm_daemon_frame_t frame = {0};
uint8_t *payload = NULL;
int received = cbm_daemon_ipc_receive_frame(connection,
RUNTIME_TEST_TIMEOUT_MS,
&frame, &payload);
bool valid = received == 1 && frame.type == CBM_DAEMON_FRAME_RESPONSE &&
frame.flags == CBM_DAEMON_RUNTIME_OP_APPLICATION_REQUEST &&
frame.length >= 16 && payload &&
runtime_test_get_u64(payload) != 0 &&
runtime_test_get_u32(payload + 8) ==
(uint32_t)expected_status &&
runtime_test_get_u32(payload + 12) == frame.length - 16;
free(payload);
return valid;
}
static long long runtime_test_last_os_error(void) {
#ifdef _WIN32
return (long long)GetLastError();
#else
return (long long)errno;
#endif
}
static bool runtime_test_fixture_start_failed(const char *tag,
const char *stage,
long long detail) {
printf(" runtime fixture startup failed: tag=%s stage=%s detail=%lld\n",
tag ? tag : "(null)", stage ? stage : "(null)", detail);
return false;
}
static bool runtime_test_fixture_start_configured(
runtime_test_fixture_t *fixture, const char *tag,
const cbm_daemon_build_identity_t *identity, uint32_t max_clients,
uint64_t lease_timeout_ms,
const cbm_daemon_runtime_application_callbacks_t *application) {
memset(fixture, 0, sizeof(*fixture));
int parent_written = snprintf(fixture->parent, sizeof(fixture->parent),
"%s/cbm-runtime-%s-XXXXXX", cbm_tmpdir(), tag);
if (parent_written <= 0 || parent_written >= (int)sizeof(fixture->parent)) {
return runtime_test_fixture_start_failed(tag, "temporary-path",
parent_written);
}
if (!cbm_mkdtemp(fixture->parent)) {
return runtime_test_fixture_start_failed(
tag, "temporary-directory", runtime_test_last_os_error());
}
if (!cbm_daemon_rendezvous_key(fixture->key)) {
return runtime_test_fixture_start_failed(
tag, "rendezvous-key", runtime_test_last_os_error());
}
fixture->endpoint =
cbm_daemon_ipc_endpoint_new(fixture->key, fixture->parent);
if (!fixture->endpoint) {
return runtime_test_fixture_start_failed(
tag, "endpoint", runtime_test_last_os_error());
}
if (!runtime_test_copy_path(
fixture->runtime_dir,
cbm_daemon_ipc_endpoint_runtime_dir(fixture->endpoint))) {
return runtime_test_fixture_start_failed(tag, "runtime-path", 0);
}
int log_written = snprintf(fixture->log_path, sizeof(fixture->log_path), "%s/conflicts.ndjson",
fixture->parent);
int rotated_written = snprintf(fixture->rotated_log_path,
sizeof(fixture->rotated_log_path), "%s.1",
fixture->log_path);
int lock_written = snprintf(fixture->lock_log_path,
sizeof(fixture->lock_log_path), "%s.lock",
fixture->log_path);
if (log_written <= 0 || log_written >= (int)sizeof(fixture->log_path)) {
return runtime_test_fixture_start_failed(tag, "conflict-log-path",
log_written);
}
if (rotated_written <= 0 ||
rotated_written >= (int)sizeof(fixture->rotated_log_path)) {
return runtime_test_fixture_start_failed(tag, "rotated-log-path",
rotated_written);
}
if (lock_written <= 0 ||
lock_written >= (int)sizeof(fixture->lock_log_path)) {
return runtime_test_fixture_start_failed(tag, "lock-log-path",
lock_written);
}
cbm_daemon_runtime_service_config_t config = {
.endpoint = fixture->endpoint,
.identity = *identity,
.conflict_log_path = fixture->log_path,
.conflict_log_cap_bytes = 64U * 1024U,
.max_clients = max_clients,
.lease_timeout_ms = lease_timeout_ms,
.request_timeout_ms = RUNTIME_TEST_TIMEOUT_MS,
.shutdown_timeout_ms = RUNTIME_TEST_TIMEOUT_MS,
};
if (application) {
config.application = *application;
}
fixture->service = cbm_daemon_runtime_service_start(&config);
if (!fixture->service) {
return runtime_test_fixture_start_failed(
tag, "service-start", runtime_test_last_os_error());
}
cbm_daemon_runtime_service_state_t state =
cbm_daemon_runtime_service_state(fixture->service);
if (state != CBM_DAEMON_RUNTIME_SERVICE_RUNNING) {
return runtime_test_fixture_start_failed(tag, "service-state",
(long long)state);
}
return true;
}
static bool runtime_test_fixture_start_limited(runtime_test_fixture_t *fixture,
const char *tag,
const cbm_daemon_build_identity_t *identity,
uint32_t max_clients) {
return runtime_test_fixture_start_configured(fixture, tag, identity,
max_clients, 5000, NULL);
}
static bool runtime_test_fixture_start(runtime_test_fixture_t *fixture, const char *tag,
const cbm_daemon_build_identity_t *identity) {
return runtime_test_fixture_start_limited(fixture, tag, identity, 8);
}
static void runtime_test_fixture_finish(runtime_test_fixture_t *fixture);
/* The public convenience constructor participates in the migration guard for
* the service's complete lifetime. free must refuse a running service without
* consuming retry authority, then prove participant release after stop. */
TEST(daemon_runtime_convenience_service_owns_participant_guard) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(&fixture, "participant", &identity);
int active = started
? cbm_daemon_ipc_legacy_generation_probe(fixture.endpoint)
: -1;
bool running_free_refused =
started && !cbm_daemon_runtime_service_free(fixture.service);
bool stopped = started && cbm_daemon_runtime_service_stop(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
bool freed = stopped &&
cbm_daemon_runtime_service_free(fixture.service);
if (freed) {
fixture.service = NULL;
}
int released = freed
? cbm_daemon_ipc_legacy_generation_probe(fixture.endpoint)
: -1;
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_EQ(active, 1);
ASSERT_TRUE(running_free_refused);
ASSERT_TRUE(stopped);
ASSERT_TRUE(freed);
ASSERT_EQ(released, 0);
PASS();
}
static bool runtime_test_fixture_start_application(
runtime_test_fixture_t *fixture, const char *tag,
const cbm_daemon_build_identity_t *identity,
runtime_application_context_t *context) {
cbm_daemon_runtime_application_callbacks_t application =
runtime_application_callbacks(context);
return runtime_test_fixture_start_configured(fixture, tag, identity, 8,
5000, &application);
}
static void runtime_test_fixture_finish(runtime_test_fixture_t *fixture) {
if (fixture->service) {
cbm_daemon_runtime_service_state_t state =
cbm_daemon_runtime_service_state(fixture->service);
if (state != CBM_DAEMON_RUNTIME_SERVICE_EXITED) {
(void)cbm_daemon_runtime_service_stop(fixture->service,
RUNTIME_TEST_TIMEOUT_MS);
}
(void)cbm_daemon_runtime_service_free(fixture->service);
}
cbm_daemon_ipc_endpoint_free(fixture->endpoint);
(void)cbm_unlink(fixture->rotated_log_path);
(void)cbm_unlink(fixture->log_path);
(void)cbm_unlink(fixture->lock_log_path);
(void)cbm_rmdir(fixture->runtime_dir);
(void)cbm_rmdir(fixture->parent);
memset(fixture, 0, sizeof(*fixture));
}
static bool runtime_test_read_log(const char *path, char out[RUNTIME_TEST_LOG_CAP]) {
FILE *file = cbm_fopen(path, "rb");
if (!file) {
return false;
}
size_t used = fread(out, 1, RUNTIME_TEST_LOG_CAP - 1, file);
bool complete = !ferror(file) && feof(file);
out[used] = '\0';
(void)fclose(file);
return complete;
}
#ifndef _WIN32
static int runtime_test_failed_host_child(const char *parent,
const char *key) {
char cache[RUNTIME_TEST_PATH_CAP];
char log_path[RUNTIME_TEST_PATH_CAP];
int cache_written = snprintf(cache, sizeof(cache), "%s/cache", parent);
int log_written = snprintf(log_path, sizeof(log_path),
"%s/logs/cbm-daemon.log", cache);
if (cache_written <= 0 || cache_written >= (int)sizeof(cache) ||
log_written <= 0 || log_written >= (int)sizeof(log_path) ||
cbm_setenv("CBM_CACHE_DIR", cache, 1) != 0) {
return 40;
}
cbm_daemon_ipc_endpoint_t *endpoint =
cbm_daemon_ipc_endpoint_new(key, parent);
atomic_int stop_requested = ATOMIC_VAR_INIT(0);
cbm_daemon_build_identity_t mismatched = runtime_test_identity(
"host-order-test", RUNTIME_BUILD_B);
cbm_daemon_host_config_t config = {
.endpoint = endpoint,
.identity = mismatched,
.executable_path = "/host-order-test",
.stop_requested = &stop_requested,
};
int run_result = endpoint ? cbm_daemon_host_run(&config) : 0;
char log[RUNTIME_TEST_LOG_CAP] = {0};
bool read = runtime_test_read_log(log_path, log);
bool failed_at_runtime =
read && strstr(log, "daemon.start_failed") != NULL &&
strstr(log, "runtime") != NULL;
bool watcher_started = read && strstr(log, "watcher.start") != NULL;
cbm_daemon_ipc_endpoint_free(endpoint);
if (run_result != -1 || !failed_at_runtime) {
return 41;
}
return watcher_started ? 42 : 0;
}
/* RED on the former host order: host_state_start launched the watcher before
* runtime fingerprint validation/listener reservation, so the isolated log
* always contained watcher.start even though no daemon could serve a client. */
TEST(daemon_host_failed_listener_reservation_starts_no_background_work) {
char parent[RUNTIME_TEST_PATH_CAP];
int written = snprintf(parent, sizeof(parent),
"%s/cbm-host-order-XXXXXX", cbm_tmpdir());
bool parent_created = written > 0 && written < (int)sizeof(parent) &&
cbm_mkdtemp(parent) != NULL;
char key[CBM_DAEMON_KEY_SIZE] = {0};
cbm_daemon_ipc_endpoint_t *endpoint =
parent_created && cbm_daemon_rendezvous_key(key)
? cbm_daemon_ipc_endpoint_new(key, parent)
: NULL;
cbm_daemon_ipc_startup_lock_t *startup = NULL;
bool setup = endpoint &&
cbm_daemon_ipc_startup_lock_try_acquire(endpoint, &startup) == 1 &&
cbm_daemon_ipc_startup_lock_prepare_handoff(startup);
pid_t child = setup ? fork() : -1;
if (child == 0) {
_exit(runtime_test_failed_host_child(parent, key));
}
int status = 0;
bool waited = child > 0 && waitpid(child, &status, 0) == child;
bool startup_released =
cbm_daemon_ipc_startup_lock_release(&startup);
cbm_daemon_ipc_endpoint_free(endpoint);
th_cleanup(parent_created ? parent : NULL);
ASSERT_TRUE(setup);
ASSERT_TRUE(child > 0);
ASSERT_TRUE(waited);
ASSERT_TRUE(startup_released);
ASSERT_TRUE(WIFEXITED(status));
ASSERT_EQ(WEXITSTATUS(status), 0);
PASS();
}
static _Noreturn void runtime_test_forced_host_shutdown_child(
const char *parent) {
char cache[RUNTIME_TEST_PATH_CAP];
int written = snprintf(cache, sizeof(cache), "%s/cache", parent);
if (written <= 0 || written >= (int)sizeof(cache) ||
cbm_setenv("CBM_CACHE_DIR", cache, 1) != 0) {
_exit(80);
}
(void)alarm(2);
cbm_daemon_host_force_terminate_for_test("noncooperative_callback");
}
static bool runtime_test_cleanup_release_never_succeeds(void *context) {
(void)context;
return false;
}
static _Noreturn void runtime_test_persistent_cleanup_failure_child(
const char *parent) {
char cache[RUNTIME_TEST_PATH_CAP];
int written = snprintf(cache, sizeof(cache), "%s/cache", parent);
if (written <= 0 || written >= (int)sizeof(cache) ||
cbm_setenv("CBM_CACHE_DIR", cache, 1) != 0) {
_exit(81);
}
cbm_daemon_host_cleanup_release_until_complete_for_test(
runtime_test_cleanup_release_never_succeeds, NULL);
/* Continuing after an unreleased native coordination claim would let the
* daemon report a clean stop that never actually completed. */
_exit(82);
}
/* Native unlock/close failures are retryable, but a persistent OS error must
* not turn daemon shutdown into an immortal process. The parent polls with a
* hard deadline and always kills/reaps a regressed child so this test itself
* can fail without hanging the rest of the suite. */
TEST(daemon_host_persistent_cleanup_release_failure_is_process_bounded) {
char parent[RUNTIME_TEST_PATH_CAP];
char log_path[RUNTIME_TEST_PATH_CAP];
int parent_written = snprintf(parent, sizeof(parent),
"%s/cbm-host-cleanup-XXXXXX", cbm_tmpdir());
bool parent_created = parent_written > 0 &&
parent_written < (int)sizeof(parent) &&
cbm_mkdtemp(parent) != NULL;
int log_written = parent_created
? snprintf(log_path, sizeof(log_path),
"%s/cache/logs/cbm-daemon.log", parent)
: -1;
bool path_ok = log_written > 0 && log_written < (int)sizeof(log_path);
pid_t child = path_ok ? fork() : -1;
if (child == 0) {
runtime_test_persistent_cleanup_failure_child(parent);
}
int status = 0;
bool completed = false;
uint64_t deadline = cbm_now_ms() + RUNTIME_TEST_TIMEOUT_MS;
while (child > 0 && cbm_now_ms() < deadline) {
pid_t waited = waitpid(child, &status, WNOHANG);
if (waited == child) {
completed = true;
break;
}
if (waited < 0 && errno != EINTR) {
break;
}
cbm_usleep(1000);
}
if (child > 0 && !completed) {
(void)kill(child, SIGKILL);
while (waitpid(child, &status, 0) < 0 && errno == EINTR) {
}
}
char log[RUNTIME_TEST_LOG_CAP] = {0};
bool durable = completed && runtime_test_read_log(log_path, log) &&
strstr(log, "daemon.forced_shutdown") != NULL &&
strstr(log, "coordination_cleanup") != NULL;
th_cleanup(parent_created ? parent : NULL);
ASSERT_TRUE(parent_created);
ASSERT_TRUE(path_ok);
ASSERT_TRUE(child > 0);
ASSERT_TRUE(completed);
ASSERT_TRUE(WIFEXITED(status));
ASSERT_EQ(WEXITSTATUS(status), EXIT_FAILURE);
ASSERT_TRUE(durable);
PASS();
}
TEST(daemon_host_forced_shutdown_is_logged_flushed_and_process_bounded) {
char parent[RUNTIME_TEST_PATH_CAP];
char log_path[RUNTIME_TEST_PATH_CAP];
int parent_written = snprintf(parent, sizeof(parent),
"%s/cbm-host-force-XXXXXX", cbm_tmpdir());
bool parent_created = parent_written > 0 &&
parent_written < (int)sizeof(parent) &&
cbm_mkdtemp(parent) != NULL;
int log_written = parent_created
? snprintf(log_path, sizeof(log_path),
"%s/cache/logs/cbm-daemon.log", parent)
: -1;
bool path_ok = log_written > 0 && log_written < (int)sizeof(log_path);
pid_t child = path_ok ? fork() : -1;
if (child == 0) {
runtime_test_forced_host_shutdown_child(parent);
}
int status = 0;
bool waited = child > 0 && waitpid(child, &status, 0) == child;
char log[RUNTIME_TEST_LOG_CAP] = {0};
bool durable = waited && runtime_test_read_log(log_path, log) &&
strstr(log, "daemon.forced_shutdown") != NULL &&
strstr(log, "noncooperative_callback") != NULL;
th_cleanup(parent_created ? parent : NULL);
ASSERT_TRUE(parent_created);
ASSERT_TRUE(path_ok);
ASSERT_TRUE(child > 0);
ASSERT_TRUE(waited);
ASSERT_TRUE(WIFEXITED(status));
ASSERT_EQ(WEXITSTATUS(status), EXIT_FAILURE);
ASSERT_TRUE(durable);
PASS();
}
#endif
TEST(daemon_runtime_exact_hello_issues_connection_bound_identity) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(&fixture, "exact-hello", &identity);
cbm_daemon_runtime_connect_result_t result = {0};
cbm_daemon_runtime_client_t *client = NULL;
bool accepted = false;
bool identity_anchored = false;
bool closed = false;
bool exited = false;
if (started) {
/* Service and client are the same process image here, exercising the
* native-identity HELLO path rather than copied-image fallback. */
client = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS, &result);
}
if (client) {
uint64_t expected_pid = runtime_test_process_id();
accepted = result.status == CBM_DAEMON_RUNTIME_CONNECT_ACCEPTED &&
result.hello_status == CBM_DAEMON_HELLO_COMPATIBLE &&
result.client_id != CBM_DAEMON_CLIENT_ID_INVALID &&
result.client_id == cbm_daemon_runtime_client_id(client);
identity_anchored =
result.authenticated_process_id == expected_pid &&
cbm_daemon_runtime_client_process_id(client) == expected_pid &&
cbm_daemon_runtime_service_client_process_id(fixture.service, result.client_id) ==
expected_pid;
closed = cbm_daemon_runtime_client_close(client, RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
exited = cbm_daemon_runtime_service_wait_exited(fixture.service,
RUNTIME_TEST_TIMEOUT_MS);
}
if (client) {
(void)cbm_daemon_runtime_client_close(client, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(accepted);
ASSERT_TRUE(identity_anchored);
ASSERT_TRUE(closed);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_activation_rejects_forged_and_malformed_without_stop) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
cbm_daemon_build_identity_t forged =
runtime_test_identity("9.9.9", RUNTIME_BUILD_B);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(
&fixture, "activation-reject", &identity);
cbm_daemon_runtime_connect_result_t owner_result = {0};
cbm_daemon_runtime_client_t *owner = NULL;
uint8_t request[RUNTIME_TEST_ACTIVATION_REQUEST_SIZE];
bool encoded = runtime_test_activation_request_encode(
request, CBM_DAEMON_RUNTIME_ACTIVATION_UPDATE, &identity);
cbm_daemon_runtime_activation_result_t short_result = {0};
cbm_daemon_runtime_activation_result_t action_result = {0};
cbm_daemon_runtime_activation_result_t abi_result = {0};
cbm_daemon_runtime_activation_result_t forged_result = {0};
bool short_rejected = false;
bool action_rejected = false;
bool abi_rejected = false;
bool forged_rejected = false;
bool unchanged = false;
bool heartbeat = false;
bool closed = false;
bool exited = false;
if (started) {
owner = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS,
&owner_result);
}
if (owner && encoded) {
short_rejected = runtime_test_raw_activation_exchange(
fixture.endpoint, request,
RUNTIME_TEST_ACTIVATION_REQUEST_SIZE - 1U,
&short_result) &&
!short_result.accepted;
runtime_test_put_u32(request, UINT32_C(99));
action_rejected = runtime_test_raw_activation_exchange(
fixture.endpoint, request,
RUNTIME_TEST_ACTIVATION_REQUEST_SIZE,
&action_result) &&
!action_result.accepted;
runtime_test_put_u32(
request, (uint32_t)CBM_DAEMON_RUNTIME_ACTIVATION_UPDATE);
runtime_test_put_u32(
request + RUNTIME_TEST_ACTIVATION_IDENTITY_OFFSET,
RUNTIME_TEST_RENDEZVOUS_ABI + 1U);
abi_rejected = runtime_test_raw_activation_exchange(
fixture.endpoint, request,
RUNTIME_TEST_ACTIVATION_REQUEST_SIZE,
&abi_result) &&
!abi_result.accepted;
forged_rejected =
cbm_daemon_runtime_request_activation_shutdown(
fixture.endpoint, &forged,
CBM_DAEMON_RUNTIME_ACTIVATION_UNINSTALL,
RUNTIME_TEST_TIMEOUT_MS, &forged_result) &&
!forged_result.accepted;
unchanged =
cbm_daemon_runtime_service_state(fixture.service) ==
CBM_DAEMON_RUNTIME_SERVICE_RUNNING &&
cbm_daemon_runtime_service_active_clients(fixture.service) == 1 &&
cbm_daemon_runtime_service_wait_for_connections(
fixture.service, 1, RUNTIME_TEST_TIMEOUT_MS);
heartbeat = cbm_daemon_runtime_client_heartbeat(
owner, RUNTIME_TEST_TIMEOUT_MS);
}
if (owner) {
closed = cbm_daemon_runtime_client_close(
owner, RUNTIME_TEST_TIMEOUT_MS);
owner = NULL;
}
if (started) {
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_EQ(owner_result.status, CBM_DAEMON_RUNTIME_CONNECT_ACCEPTED);
ASSERT_TRUE(encoded);
ASSERT_TRUE(short_rejected);
ASSERT_TRUE(action_rejected);
ASSERT_TRUE(abi_rejected);
ASSERT_TRUE(forged_rejected);
ASSERT_TRUE(unchanged);
ASSERT_TRUE(heartbeat);
ASSERT_TRUE(closed);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_activation_ack_snapshots_then_interrupts_all_clients) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(
&fixture, "activation-drain", &identity);
cbm_daemon_runtime_connect_result_t first_result = {0};
cbm_daemon_runtime_connect_result_t second_result = {0};
cbm_daemon_runtime_client_t *first = NULL;
cbm_daemon_runtime_client_t *second = NULL;
cbm_daemon_runtime_activation_result_t activation = {0};
bool requested = false;
bool first_interrupted = false;
bool second_interrupted = false;
bool exited = false;
atomic_store_explicit(&runtime_activation_shutdown_log_seen, false,
memory_order_release);
cbm_log_set_sink(runtime_test_activation_shutdown_sink);
if (started) {
first = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS,
&first_result);
second = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS,
&second_result);
}
if (first && second) {
requested = cbm_daemon_runtime_request_activation_shutdown(
fixture.endpoint, &identity,
CBM_DAEMON_RUNTIME_ACTIVATION_UPDATE,
RUNTIME_TEST_TIMEOUT_MS, &activation);
first_interrupted = !cbm_daemon_runtime_client_heartbeat(
first, RUNTIME_TEST_TIMEOUT_MS);
second_interrupted = !cbm_daemon_runtime_client_heartbeat(
second, RUNTIME_TEST_TIMEOUT_MS);
}
cbm_log_set_sink(NULL);
if (first) {
(void)cbm_daemon_runtime_client_close(first,
RUNTIME_TEST_TIMEOUT_MS);
first = NULL;
}
if (second) {
(void)cbm_daemon_runtime_client_close(second,
RUNTIME_TEST_TIMEOUT_MS);
second = NULL;
}
if (started) {
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_EQ(first_result.status, CBM_DAEMON_RUNTIME_CONNECT_ACCEPTED);
ASSERT_EQ(second_result.status, CBM_DAEMON_RUNTIME_CONNECT_ACCEPTED);
ASSERT_TRUE(requested);
ASSERT_TRUE(activation.accepted);
ASSERT_EQ(activation.active_clients, 2);
/* The one-shot activation requester is not part of the drain snapshot. */
ASSERT_EQ(activation.active_connections, 2);
ASSERT_TRUE(atomic_load_explicit(&runtime_activation_shutdown_log_seen,
memory_order_acquire));
ASSERT_TRUE(first_interrupted);
ASSERT_TRUE(second_interrupted);
ASSERT_TRUE(exited);
PASS();
}
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
TEST(daemon_runtime_activation_accepts_authenticated_different_build) {
cbm_daemon_build_identity_t active_identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
char directory[RUNTIME_TEST_PATH_CAP] = {0};
char foreign_image[RUNTIME_TEST_PATH_CAP] = {0};
int directory_written = snprintf(
directory, sizeof(directory), "%s/cbm-runtime-activation-XXXXXX",
cbm_tmpdir());
bool directory_created = directory_written > 0 &&
directory_written < (int)sizeof(directory) &&
cbm_mkdtemp(directory) != NULL;
int image_written = directory_created
? snprintf(foreign_image, sizeof(foreign_image),
"%s/foreign-activation", directory)
: -1;
bool copied = image_written > 0 &&
image_written < (int)sizeof(foreign_image) &&
runtime_test_copy_self_image(foreign_image);
#ifdef __APPLE__
/* Appending an overlay invalidates Mach-O strict validation. A distinct
* signing identifier changes the executable bytes while keeping the copy
* runnable, exactly like the mapped-main-image adversarial fixture. */
bool changed = copied;
bool runnable = changed && runtime_test_mac_ad_hoc_sign(foreign_image);
#else
bool changed = copied && runtime_test_append_image_marker(foreign_image);
bool runnable = changed;
#endif
char foreign_build[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
bool fingerprinted =
runnable && cbm_daemon_build_fingerprint_file(foreign_image,
foreign_build);
bool differs = fingerprinted &&
strcmp(foreign_build,
active_identity.build_fingerprint) != 0;
cbm_daemon_build_identity_t foreign_identity =
runtime_test_identity("9.9.9", foreign_build);
/* Finalize the foreign executable before the runtime starts any worker
* threads. In particular, macOS code signing is an external process; the
* test must not fork that helper from the live multithreaded daemon. The
* immutable signed copy remains the actual peer image authenticated by
* the activation request below. */
runtime_test_fixture_t fixture;
memset(&fixture, 0, sizeof(fixture));
bool started = differs && runtime_test_fixture_start(
&fixture, "activation-foreign",
&active_identity);
cbm_daemon_runtime_connect_result_t owner_result = {0};
cbm_daemon_runtime_client_t *owner = NULL;
if (started) {
owner = cbm_daemon_runtime_client_connect(
fixture.endpoint, &active_identity, RUNTIME_TEST_TIMEOUT_MS,
&owner_result);
}
int foreign_exit = -1;
bool foreign_ran = owner && differs &&
runtime_test_run_activation_image(
foreign_image, &fixture, &foreign_identity,
CBM_DAEMON_RUNTIME_ACTIVATION_INSTALL,
&foreign_exit);
bool owner_interrupted = owner && foreign_ran &&
!cbm_daemon_runtime_client_heartbeat(
owner, RUNTIME_TEST_TIMEOUT_MS);
if (owner) {
(void)cbm_daemon_runtime_client_close(owner,
RUNTIME_TEST_TIMEOUT_MS);
owner = NULL;
}
bool exited = started && cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
runtime_test_fixture_finish(&fixture);
if (image_written > 0 && image_written < (int)sizeof(foreign_image)) {
(void)cbm_unlink(foreign_image);
}
if (directory_created) {
(void)cbm_rmdir(directory);
}
ASSERT_TRUE(started);
ASSERT_EQ(owner_result.status, CBM_DAEMON_RUNTIME_CONNECT_ACCEPTED);
ASSERT_TRUE(directory_created);
ASSERT_TRUE(copied);
ASSERT_TRUE(changed);
ASSERT_TRUE(runnable);
ASSERT_TRUE(fingerprinted);
ASSERT_TRUE(differs);
ASSERT_TRUE(foreign_ran);
ASSERT_EQ(foreign_exit, 0);
ASSERT_TRUE(owner_interrupted);
ASSERT_TRUE(exited);
PASS();
}
#endif
TEST(daemon_runtime_rendezvous_layout_is_frozen_and_detailed_abi_independent) {
cbm_daemon_build_identity_t first =
runtime_test_identity("2.4.0", runtime_test_self_build());
cbm_daemon_build_identity_t different_detail = first;
different_detail.protocol_abi = 0;
different_detail.store_abi = 0;
different_detail.feature_abi = 0;
uint8_t first_wire[CBM_DAEMON_RENDEZVOUS_REQUEST_SIZE];
uint8_t second_wire[CBM_DAEMON_RENDEZVOUS_REQUEST_SIZE];
bool first_encoded =
cbm_daemon_runtime_hello_request_encode(first_wire, &first);
bool second_encoded = cbm_daemon_runtime_hello_request_encode(
second_wire, &different_detail);
ASSERT_TRUE(first_encoded);
ASSERT_TRUE(second_encoded);
ASSERT_EQ(CBM_DAEMON_RENDEZVOUS_REQUEST_SIZE,
RUNTIME_TEST_RENDEZVOUS_REQUEST_SIZE);
ASSERT_EQ(CBM_DAEMON_RENDEZVOUS_RESPONSE_SIZE,
RUNTIME_TEST_RENDEZVOUS_RESPONSE_SIZE);
ASSERT_EQ(CBM_DAEMON_RENDEZVOUS_VERSION_TEXT_CAP,
CBM_DAEMON_VERSION_TEXT_SIZE);
ASSERT_EQ(CBM_DAEMON_RENDEZVOUS_BUILD_FINGERPRINT_CAP,
CBM_DAEMON_BUILD_FINGERPRINT_SIZE);
ASSERT_EQ(CBM_DAEMON_RENDEZVOUS_MESSAGE_CAP,
CBM_DAEMON_CONFLICT_MESSAGE_SIZE);
ASSERT_EQ(runtime_test_get_u32(first_wire),
RUNTIME_TEST_RENDEZVOUS_ABI);
ASSERT_TRUE(runtime_test_fixed_string_equals(
first_wire + RUNTIME_TEST_RENDEZVOUS_VERSION_OFFSET,
CBM_DAEMON_VERSION_TEXT_SIZE, first.semantic_version));
ASSERT_TRUE(runtime_test_fixed_string_equals(
first_wire + RUNTIME_TEST_RENDEZVOUS_BUILD_OFFSET,
CBM_DAEMON_BUILD_FINGERPRINT_SIZE, first.build_fingerprint));
ASSERT_EQ(memcmp(first_wire, second_wire, sizeof(first_wire)), 0);
PASS();
}
TEST(daemon_runtime_future_generation_gets_stable_explicit_conflict) {
const char *active_build = runtime_test_self_build();
cbm_daemon_build_identity_t active =
runtime_test_identity("2.4.0", active_build);
cbm_daemon_build_identity_t future =
runtime_test_identity("9.0.0-future-wire-v2", RUNTIME_BUILD_B);
future.protocol_abi = active.protocol_abi + 1000;
future.store_abi = active.store_abi + 2000;
future.feature_abi = active.feature_abi + 3000;
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(
&fixture, "future-generation", &active);
cbm_daemon_runtime_connect_result_t owner_result = {0};
cbm_daemon_runtime_client_t *owner = NULL;
cbm_daemon_ipc_connection_t *future_connection = NULL;
uint8_t future_wire[CBM_DAEMON_RENDEZVOUS_REQUEST_SIZE];
bool encoded = false;
bool sent = false;
bool explicit_conflict = false;
bool logged = false;
bool exited = false;
cbm_daemon_frame_t response_frame = {0};
uint8_t *response_payload = NULL;
char log[RUNTIME_TEST_LOG_CAP] = {0};
char expected_message[CBM_DAEMON_CONFLICT_MESSAGE_SIZE] = {0};
int expected_length = snprintf(
expected_message, sizeof(expected_message),
"CBM could not start because a conflicting CBM process is active "
"(version; active version %s, build %s; requested version %s, build %s). "
"Close all CBM sessions and commands, then retry.",
active.semantic_version, active_build, future.semantic_version,
future.build_fingerprint);
bool expected_message_valid =
expected_length > 0 && (size_t)expected_length < sizeof(expected_message);
if (started) {
owner = cbm_daemon_runtime_client_connect(
fixture.endpoint, &active, RUNTIME_TEST_TIMEOUT_MS, &owner_result);
}
if (owner) {
encoded = cbm_daemon_runtime_hello_request_encode(future_wire, &future);
future_connection = cbm_daemon_ipc_connect(
fixture.endpoint, RUNTIME_TEST_TIMEOUT_MS);
}
if (future_connection && encoded) {
/* A future generation sends only the permanent identity envelope here;
* its detailed runtime layout is negotiated by exact executable build,
* never added to this stable endpoint message. */
sent = cbm_daemon_ipc_send_frame(
future_connection, CBM_DAEMON_FRAME_REQUEST,
CBM_DAEMON_RUNTIME_OP_HELLO, future_wire,
RUNTIME_TEST_RENDEZVOUS_REQUEST_SIZE);
int received = cbm_daemon_ipc_receive_frame(
future_connection, RUNTIME_TEST_TIMEOUT_MS, &response_frame,
&response_payload);
explicit_conflict =
expected_message_valid && received == 1 && response_payload &&
response_frame.type == CBM_DAEMON_FRAME_RESPONSE &&
response_frame.flags == CBM_DAEMON_RUNTIME_OP_HELLO &&
response_frame.length == RUNTIME_TEST_RENDEZVOUS_RESPONSE_SIZE &&
runtime_test_get_u32(response_payload) ==
CBM_DAEMON_RUNTIME_CONNECT_CONFLICT &&
runtime_test_get_u32(response_payload + 4) ==
CBM_DAEMON_HELLO_VERSION_CONFLICT &&
runtime_test_fixed_string_equals(
response_payload + RUNTIME_TEST_RENDEZVOUS_ACTIVE_VERSION_OFFSET,
CBM_DAEMON_VERSION_TEXT_SIZE, active.semantic_version) &&
runtime_test_fixed_string_equals(
response_payload + RUNTIME_TEST_RENDEZVOUS_ACTIVE_BUILD_OFFSET,
CBM_DAEMON_BUILD_FINGERPRINT_SIZE, active_build) &&
runtime_test_fixed_string_equals(
response_payload + RUNTIME_TEST_RENDEZVOUS_REQUESTED_VERSION_OFFSET,
CBM_DAEMON_VERSION_TEXT_SIZE, future.semantic_version) &&
runtime_test_fixed_string_equals(
response_payload + RUNTIME_TEST_RENDEZVOUS_REQUESTED_BUILD_OFFSET,
CBM_DAEMON_BUILD_FINGERPRINT_SIZE,
future.build_fingerprint) &&
runtime_test_fixed_string_equals(
response_payload + RUNTIME_TEST_RENDEZVOUS_MESSAGE_OFFSET,
CBM_DAEMON_CONFLICT_MESSAGE_SIZE, expected_message);
}
cbm_daemon_ipc_connection_close(future_connection);
future_connection = NULL;
free(response_payload);
response_payload = NULL;
if (owner) {
logged = runtime_test_read_log(fixture.log_path, log) &&
strstr(log, "\"reason\":\"version\"") != NULL &&
strstr(log, active_build) != NULL &&
strstr(log, RUNTIME_BUILD_B) != NULL;
(void)cbm_daemon_runtime_client_close(owner,
RUNTIME_TEST_TIMEOUT_MS);
owner = NULL;
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
cbm_daemon_ipc_connection_close(future_connection);
free(response_payload);
if (owner) {
(void)cbm_daemon_runtime_client_close(owner,
RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(encoded);
ASSERT_TRUE(sent);
ASSERT_TRUE(explicit_conflict);
ASSERT_TRUE(logged);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_matching_clients_share_one_service_endpoint) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(&fixture, "shared-endpoint", &identity);
cbm_daemon_ipc_endpoint_t *same_endpoint = NULL;
cbm_daemon_runtime_client_t *first = NULL;
cbm_daemon_runtime_client_t *second = NULL;
cbm_daemon_runtime_connect_result_t first_result = {0};
cbm_daemon_runtime_connect_result_t second_result = {0};
bool same_address = false;
bool both_registered = false;
bool one_remains = false;
bool exited = false;
char key[CBM_DAEMON_KEY_SIZE];
if (started && cbm_daemon_rendezvous_key(key)) {
same_endpoint = cbm_daemon_ipc_endpoint_new(key, fixture.parent);
}
if (same_endpoint) {
same_address =
strcmp(cbm_daemon_ipc_endpoint_address(fixture.endpoint),
cbm_daemon_ipc_endpoint_address(same_endpoint)) == 0;
first = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS, &first_result);
second = cbm_daemon_runtime_client_connect(same_endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS, &second_result);
}
if (first && second) {
both_registered = first_result.client_id != second_result.client_id &&
cbm_daemon_runtime_service_active_clients(fixture.service) == 2;
(void)cbm_daemon_runtime_client_close(first, RUNTIME_TEST_TIMEOUT_MS);
first = NULL;
one_remains = cbm_daemon_runtime_service_wait_for_clients(
fixture.service, 1, RUNTIME_TEST_TIMEOUT_MS);
(void)cbm_daemon_runtime_client_close(second, RUNTIME_TEST_TIMEOUT_MS);
second = NULL;
exited = cbm_daemon_runtime_service_wait_exited(fixture.service,
RUNTIME_TEST_TIMEOUT_MS);
}
if (second) {
(void)cbm_daemon_runtime_client_close(second, RUNTIME_TEST_TIMEOUT_MS);
}
if (first) {
(void)cbm_daemon_runtime_client_close(first, RUNTIME_TEST_TIMEOUT_MS);
}
cbm_daemon_ipc_endpoint_free(same_endpoint);
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(same_address);
ASSERT_TRUE(both_registered);
ASSERT_TRUE(one_remains);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_same_version_different_build_is_visible_and_logged) {
const char *active_build = runtime_test_self_build();
cbm_daemon_build_identity_t active = runtime_test_identity("2.4.0", active_build);
cbm_daemon_build_identity_t rebuilt = runtime_test_identity("2.4.0", RUNTIME_BUILD_B);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(&fixture, "build-conflict", &active);
cbm_daemon_runtime_connect_result_t owner_result = {0};
cbm_daemon_runtime_connect_result_t conflict_result = {0};
cbm_daemon_runtime_client_t *owner = NULL;
cbm_daemon_runtime_client_t *rejected = NULL;
bool explicit_conflict = false;
bool logged = false;
bool owner_unchanged = false;
bool exited = false;
char log[RUNTIME_TEST_LOG_CAP] = {0};
if (started) {
owner = cbm_daemon_runtime_client_connect(fixture.endpoint, &active,
RUNTIME_TEST_TIMEOUT_MS, &owner_result);
}
if (owner) {
rejected = cbm_daemon_runtime_client_connect(fixture.endpoint, &rebuilt,
RUNTIME_TEST_TIMEOUT_MS, &conflict_result);
explicit_conflict =
rejected == NULL &&
conflict_result.status == CBM_DAEMON_RUNTIME_CONNECT_CONFLICT &&
conflict_result.hello_status == CBM_DAEMON_HELLO_BUILD_CONFLICT &&
strstr(conflict_result.message, "could not start") != NULL &&
strstr(conflict_result.message, active_build) != NULL &&
strstr(conflict_result.message, RUNTIME_BUILD_B) != NULL;
owner_unchanged =
cbm_daemon_runtime_service_active_clients(fixture.service) == 1;
logged = runtime_test_read_log(fixture.log_path, log) &&
strstr(log, "daemon.version_conflict") != NULL &&
strstr(log, "\"reason\":\"build\"") != NULL &&
strstr(log, active_build) != NULL && strstr(log, RUNTIME_BUILD_B) != NULL;
(void)cbm_daemon_runtime_client_close(owner, RUNTIME_TEST_TIMEOUT_MS);
owner = NULL;
exited = cbm_daemon_runtime_service_wait_exited(fixture.service,
RUNTIME_TEST_TIMEOUT_MS);
}
if (rejected) {
(void)cbm_daemon_runtime_client_close(rejected, RUNTIME_TEST_TIMEOUT_MS);
}
if (owner) {
(void)cbm_daemon_runtime_client_close(owner, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(explicit_conflict);
ASSERT_TRUE(owner_unchanged);
ASSERT_TRUE(logged);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_conflict_log_failure_uses_operation_log_fallback) {
const char *active_build = runtime_test_self_build();
cbm_daemon_build_identity_t active = runtime_test_identity("2.4.0", active_build);
cbm_daemon_build_identity_t rebuilt = runtime_test_identity("2.4.0", RUNTIME_BUILD_B);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(&fixture, "conflict-log-fallback", &active);
bool obstruction_created = started && cbm_mkdir_p(fixture.log_path, 0700);
cbm_daemon_runtime_connect_result_t owner_result = {0};
cbm_daemon_runtime_connect_result_t conflict_result = {0};
cbm_daemon_runtime_client_t *owner = NULL;
cbm_daemon_runtime_client_t *rejected = NULL;
CBMLogLevel prior_level = cbm_log_get_level();
bool explicit_conflict = false;
bool exited = false;
atomic_store_explicit(&runtime_conflict_log_fallback_seen, false,
memory_order_release);
if (obstruction_created) {
cbm_log_set_level(CBM_LOG_ERROR);
cbm_log_set_sink(runtime_test_conflict_log_fallback_sink);
owner = cbm_daemon_runtime_client_connect(
fixture.endpoint, &active, RUNTIME_TEST_TIMEOUT_MS, &owner_result);
}
if (owner) {
rejected = cbm_daemon_runtime_client_connect(
fixture.endpoint, &rebuilt, RUNTIME_TEST_TIMEOUT_MS,
&conflict_result);
explicit_conflict =
rejected == NULL &&
conflict_result.status == CBM_DAEMON_RUNTIME_CONNECT_CONFLICT &&
conflict_result.hello_status == CBM_DAEMON_HELLO_BUILD_CONFLICT;
(void)cbm_daemon_runtime_client_close(owner,
RUNTIME_TEST_TIMEOUT_MS);
owner = NULL;
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
cbm_log_set_sink(NULL);
cbm_log_set_level(prior_level);
if (rejected) {
(void)cbm_daemon_runtime_client_close(rejected,
RUNTIME_TEST_TIMEOUT_MS);
}
if (owner) {
(void)cbm_daemon_runtime_client_close(owner,
RUNTIME_TEST_TIMEOUT_MS);
}
bool fallback_seen = atomic_load_explicit(
&runtime_conflict_log_fallback_seen, memory_order_acquire);
if (obstruction_created) {
(void)cbm_rmdir(fixture.log_path);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(obstruction_created);
ASSERT_TRUE(explicit_conflict);
ASSERT_TRUE(fallback_seen);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_disconnect_releases_only_connection_subscriptions) {
static const char project[] = "runtime-shared-project";
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(&fixture, "owned-subscriptions", &identity);
cbm_daemon_runtime_client_t *first = NULL;
cbm_daemon_runtime_client_t *second = NULL;
cbm_daemon_runtime_connect_result_t first_result = {0};
cbm_daemon_runtime_connect_result_t second_result = {0};
cbm_daemon_subscription_id_t first_subscription = CBM_DAEMON_SUBSCRIPTION_ID_INVALID;
cbm_daemon_subscription_id_t second_subscription = CBM_DAEMON_SUBSCRIPTION_ID_INVALID;
bool subscribed = false;
bool second_survived = false;
bool reaped = false;
bool exited = false;
if (started) {
first = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS, &first_result);
second = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS, &second_result);
}
if (first && second) {
cbm_daemon_subscription_result_t first_status =
cbm_daemon_runtime_client_job_subscribe(first, project, &first_subscription,
RUNTIME_TEST_TIMEOUT_MS);
cbm_daemon_subscription_result_t second_status =
cbm_daemon_runtime_client_job_subscribe(second, project, &second_subscription,
RUNTIME_TEST_TIMEOUT_MS);
subscribed = first_status == CBM_DAEMON_SUBSCRIPTION_STARTED &&
second_status == CBM_DAEMON_SUBSCRIPTION_JOINED &&
first_subscription != CBM_DAEMON_SUBSCRIPTION_ID_INVALID &&
second_subscription != CBM_DAEMON_SUBSCRIPTION_ID_INVALID &&
first_subscription != second_subscription &&
cbm_daemon_runtime_service_job_subscribers(fixture.service, project) == 2;
(void)cbm_daemon_runtime_client_close(first, RUNTIME_TEST_TIMEOUT_MS);
first = NULL;
second_survived = cbm_daemon_runtime_service_wait_for_clients(
fixture.service, 1, RUNTIME_TEST_TIMEOUT_MS) &&
cbm_daemon_runtime_service_job_subscribers(fixture.service, project) ==
1 &&
cbm_daemon_runtime_client_job_unsubscribe(
second, second_subscription, RUNTIME_TEST_TIMEOUT_MS) &&
cbm_daemon_runtime_service_job_subscribers(fixture.service, project) ==
0;
reaped = cbm_daemon_runtime_service_job_reaped(fixture.service, project);
(void)cbm_daemon_runtime_client_close(second, RUNTIME_TEST_TIMEOUT_MS);
second = NULL;
exited = cbm_daemon_runtime_service_wait_exited(fixture.service,
RUNTIME_TEST_TIMEOUT_MS);
}
if (second) {
(void)cbm_daemon_runtime_client_close(second, RUNTIME_TEST_TIMEOUT_MS);
}
if (first) {
(void)cbm_daemon_runtime_client_close(first, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(subscribed);
ASSERT_TRUE(second_survived);
ASSERT_TRUE(reaped);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_final_disconnect_automatically_exits_within_bound) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(&fixture, "bounded-exit", &identity);
cbm_daemon_runtime_client_t *client = NULL;
cbm_daemon_runtime_connect_result_t result = {0};
bool terminal_transition = false;
bool exited = false;
if (started) {
client = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS, &result);
}
if (client) {
(void)cbm_daemon_runtime_client_close(client, RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
cbm_daemon_runtime_service_state_t after_close =
cbm_daemon_runtime_service_state(fixture.service);
terminal_transition = after_close == CBM_DAEMON_RUNTIME_SERVICE_STOPPING ||
after_close == CBM_DAEMON_RUNTIME_SERVICE_EXITED;
exited = cbm_daemon_runtime_service_wait_exited(fixture.service,
RUNTIME_TEST_TIMEOUT_MS);
}
if (client) {
(void)cbm_daemon_runtime_client_close(client, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(terminal_transition);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_authenticated_idle_connection_outlives_lease_interval) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_configured(
&fixture, "idle-connection", &identity, 8, 20, NULL);
cbm_daemon_runtime_connect_result_t result = {0};
cbm_daemon_runtime_client_t *client = NULL;
bool remained_connected = false;
bool exited = false;
if (started) {
client = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS,
&result);
}
if (client) {
struct timespec beyond_lease = {.tv_sec = 0, .tv_nsec = 60000000};
(void)cbm_nanosleep(&beyond_lease, NULL);
remained_connected =
cbm_daemon_runtime_service_active_clients(fixture.service) == 1 &&
cbm_daemon_runtime_client_heartbeat(client,
RUNTIME_TEST_TIMEOUT_MS);
(void)cbm_daemon_runtime_client_close(client,
RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
if (client) {
(void)cbm_daemon_runtime_client_close(client,
RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(remained_connected);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_connection_cap_covers_slow_hello_and_stopping_is_terminal) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_limited(&fixture, "connection-cap", &identity, 2);
cbm_daemon_ipc_connection_t *slow_hello = NULL;
cbm_daemon_runtime_client_t *accepted = NULL;
cbm_daemon_runtime_client_t *overflow = NULL;
cbm_daemon_runtime_client_t *resurrection = NULL;
cbm_daemon_runtime_connect_result_t accepted_result = {0};
cbm_daemon_runtime_connect_result_t overflow_result = {0};
cbm_daemon_runtime_connect_result_t resurrection_result = {0};
bool slow_slot_counted = false;
bool capacity_rejected = false;
bool slow_slot_released = false;
bool exited = false;
bool no_resurrection = false;
if (started) {
slow_hello = cbm_daemon_ipc_connect(fixture.endpoint, RUNTIME_TEST_TIMEOUT_MS);
}
if (slow_hello) {
slow_slot_counted = cbm_daemon_runtime_service_wait_for_connections(
fixture.service, 1, RUNTIME_TEST_TIMEOUT_MS);
accepted = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS, &accepted_result);
}
if (accepted) {
overflow = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS, &overflow_result);
capacity_rejected =
overflow == NULL && overflow_result.status == CBM_DAEMON_RUNTIME_CONNECT_REJECTED &&
strstr(overflow_result.message, "capacity") != NULL &&
cbm_daemon_runtime_service_active_connections(fixture.service) == 2 &&
cbm_daemon_runtime_service_active_clients(fixture.service) == 1;
cbm_daemon_ipc_connection_close(slow_hello);
slow_hello = NULL;
slow_slot_released = cbm_daemon_runtime_service_wait_for_connections(
fixture.service, 1, RUNTIME_TEST_TIMEOUT_MS);
(void)cbm_daemon_runtime_client_close(accepted, RUNTIME_TEST_TIMEOUT_MS);
accepted = NULL;
exited = cbm_daemon_runtime_service_wait_exited(fixture.service,
RUNTIME_TEST_TIMEOUT_MS);
resurrection = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity, 100,
&resurrection_result);
cbm_daemon_runtime_service_state_t terminal_state =
cbm_daemon_runtime_service_state(fixture.service);
no_resurrection =
resurrection == NULL &&
(resurrection_result.status == CBM_DAEMON_RUNTIME_CONNECT_ERROR ||
resurrection_result.status == CBM_DAEMON_RUNTIME_CONNECT_REJECTED) &&
cbm_daemon_runtime_service_active_clients(fixture.service) == 0 &&
(terminal_state == CBM_DAEMON_RUNTIME_SERVICE_STOPPING ||
terminal_state == CBM_DAEMON_RUNTIME_SERVICE_EXITED);
}
if (resurrection) {
(void)cbm_daemon_runtime_client_close(resurrection, RUNTIME_TEST_TIMEOUT_MS);
}
if (overflow) {
(void)cbm_daemon_runtime_client_close(overflow, RUNTIME_TEST_TIMEOUT_MS);
}
if (accepted) {
(void)cbm_daemon_runtime_client_close(accepted, RUNTIME_TEST_TIMEOUT_MS);
}
cbm_daemon_ipc_connection_close(slow_hello);
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(slow_slot_counted);
ASSERT_TRUE(capacity_rejected);
ASSERT_TRUE(slow_slot_released);
ASSERT_TRUE(exited);
ASSERT_TRUE(no_resurrection);
PASS();
}
TEST(daemon_runtime_rejects_forged_identity_extension) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start(&fixture, "forged-identity", &identity);
cbm_daemon_ipc_connection_t *raw = NULL;
uint8_t forged[CBM_DAEMON_RENDEZVOUS_REQUEST_SIZE +
sizeof(uint64_t) * 2] = {0};
uint64_t forged_client_id = UINT64_MAX - 1;
uint64_t forged_process_id = UINT64_MAX;
bool encoded = false;
bool sent = false;
bool rejected = false;
cbm_daemon_frame_t response_frame = {0};
uint8_t *response_payload = NULL;
if (started) {
encoded = cbm_daemon_runtime_hello_request_encode(forged, &identity);
memcpy(forged + CBM_DAEMON_RENDEZVOUS_REQUEST_SIZE,
&forged_client_id,
sizeof(forged_client_id));
memcpy(forged + CBM_DAEMON_RENDEZVOUS_REQUEST_SIZE +
sizeof(forged_client_id),
&forged_process_id, sizeof(forged_process_id));
raw = cbm_daemon_ipc_connect(fixture.endpoint, RUNTIME_TEST_TIMEOUT_MS);
}
if (raw && encoded) {
sent = cbm_daemon_ipc_send_frame(raw, CBM_DAEMON_FRAME_REQUEST,
CBM_DAEMON_RUNTIME_OP_HELLO, forged,
(uint32_t)sizeof(forged));
int received = cbm_daemon_ipc_receive_frame(raw, RUNTIME_TEST_TIMEOUT_MS,
&response_frame, &response_payload);
rejected = received != 1 &&
cbm_daemon_runtime_service_active_clients(fixture.service) == 0;
}
free(response_payload);
cbm_daemon_ipc_connection_close(raw);
/* A malformed peer must not poison the stable service for valid clients. */
cbm_daemon_runtime_connect_result_t valid_result = {0};
cbm_daemon_runtime_client_t *valid = NULL;
bool valid_after_rejection = false;
bool exited = false;
if (started) {
valid = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS, &valid_result);
}
if (valid) {
valid_after_rejection =
valid_result.status == CBM_DAEMON_RUNTIME_CONNECT_ACCEPTED &&
valid_result.authenticated_process_id == runtime_test_process_id() &&
valid_result.client_id != forged_client_id;
(void)cbm_daemon_runtime_client_close(valid, RUNTIME_TEST_TIMEOUT_MS);
valid = NULL;
exited = cbm_daemon_runtime_service_wait_exited(fixture.service,
RUNTIME_TEST_TIMEOUT_MS);
}
if (valid) {
(void)cbm_daemon_runtime_client_close(valid, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(encoded);
ASSERT_TRUE(sent);
ASSERT_TRUE(rejected);
ASSERT_TRUE(valid_after_rejection);
ASSERT_TRUE(exited);
PASS();
}
TEST(daemon_runtime_application_response_roundtrip_is_byte_exact) {
static const uint8_t request[] = {
0x00, 0x7f, 0x80, 0xff, 'c', 'b', 'm', 0x00, 0x13,
};
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, false);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-roundtrip", &identity, &context);
cbm_daemon_runtime_connect_result_t result = {0};
cbm_daemon_runtime_client_t *client = NULL;
uint8_t *response = NULL;
uint32_t response_length = 0;
cbm_daemon_runtime_application_status_t status =
CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR;
bool exact = false;
bool closed = false;
bool exited = false;
if (started) {
client = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS,
&result);
}
if (client) {
status = cbm_daemon_runtime_client_application_request(
client, request, (uint32_t)sizeof(request), &response,
&response_length, RUNTIME_TEST_TIMEOUT_MS);
exact = status == CBM_DAEMON_RUNTIME_APPLICATION_OK &&
response_length == sizeof(request) && response &&
memcmp(response, request, sizeof(request)) == 0;
free(response);
response = NULL;
closed = cbm_daemon_runtime_client_close(client,
RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
free(response);
if (client) {
(void)cbm_daemon_runtime_client_close(client,
RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(exact);
ASSERT_TRUE(closed);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.opened), 1);
ASSERT_EQ(atomic_load(&context.requests), 1);
ASSERT_EQ(atomic_load(&context.cancelled), 1);
ASSERT_EQ(atomic_load(&context.closed), 1);
PASS();
}
TEST(daemon_runtime_final_disconnect_rejects_blocked_provisional_session) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, false);
atomic_store_explicit(&context.block_second_open, true,
memory_order_release);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-open-race", &identity, &context);
cbm_daemon_runtime_connect_result_t owner_result = {0};
cbm_daemon_runtime_client_t *owner = NULL;
runtime_application_connect_call_t contender = {
.identity = identity,
};
atomic_init(&contender.completed, false);
cbm_thread_t connect_thread;
int connect_thread_create_rc = -1;
int connect_thread_join_rc = -1;
bool connect_thread_started = false;
bool provisional_started = false;
bool owner_closed = false;
bool shutdown_won = false;
bool contender_accepted = false;
bool exited = false;
if (started) {
owner = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS,
&owner_result);
}
if (owner) {
contender.endpoint = fixture.endpoint;
connect_thread_create_rc = cbm_thread_create(
&connect_thread, 128U * 1024U,
runtime_application_client_connect_thread, &contender);
connect_thread_started = connect_thread_create_rc == 0;
provisional_started = connect_thread_started &&
runtime_test_wait_atomic_bool(
&context.second_open_started,
RUNTIME_TEST_TIMEOUT_MS);
}
if (provisional_started) {
owner_closed = cbm_daemon_runtime_client_close(
owner, RUNTIME_TEST_TIMEOUT_MS);
owner = NULL;
shutdown_won = cbm_daemon_runtime_service_state(fixture.service) ==
CBM_DAEMON_RUNTIME_SERVICE_STOPPING;
}
/* Release on every setup outcome so neither the server worker nor the
* helper can retain stack-owned test state during cleanup. */
atomic_store_explicit(&context.release_second_open, true,
memory_order_release);
if (connect_thread_started) {
connect_thread_join_rc = cbm_thread_join(&connect_thread);
if (connect_thread_join_rc == 0) {
connect_thread_started = false;
}
}
if (connect_thread_started) {
while (!atomic_load_explicit(&contender.completed,
memory_order_acquire)) {
struct timespec pause = {.tv_sec = 0, .tv_nsec = 1000000};
(void)cbm_nanosleep(&pause, NULL);
}
}
contender_accepted = contender.client != NULL;
if (owner) {
(void)cbm_daemon_runtime_client_close(owner,
RUNTIME_TEST_TIMEOUT_MS);
owner = NULL;
}
if (contender.client) {
(void)cbm_daemon_runtime_client_close(contender.client,
RUNTIME_TEST_TIMEOUT_MS);
contender.client = NULL;
}
if (started) {
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_EQ(owner_result.status, CBM_DAEMON_RUNTIME_CONNECT_ACCEPTED);
ASSERT_EQ(connect_thread_create_rc, 0);
ASSERT_TRUE(provisional_started);
ASSERT_TRUE(owner_closed);
ASSERT_TRUE(shutdown_won);
ASSERT_EQ(connect_thread_join_rc, 0);
ASSERT_TRUE(atomic_load_explicit(&contender.completed,
memory_order_acquire));
ASSERT_FALSE(contender_accepted);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.opened), 2);
ASSERT_EQ(atomic_load(&context.cancelled), 2);
ASSERT_EQ(atomic_load(&context.closed), 2);
PASS();
}
TEST(daemon_runtime_request_cancel_is_exact_and_session_remains_usable) {
static const uint8_t blocking_request[] = {'b', 'l', 'o', 'c', 'k'};
static const uint8_t next_request[] = {0xde, 0xad, 0x00, 0xbe, 0xef};
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, true);
atomic_bool request_thread_completed;
atomic_init(&request_thread_completed, false);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-request-cancel", &identity, &context);
cbm_daemon_runtime_connect_result_t result = {0};
cbm_daemon_runtime_client_t *client = NULL;
cbm_daemon_runtime_application_token_t request_token =
CBM_DAEMON_RUNTIME_APPLICATION_TOKEN_INVALID;
runtime_application_client_call_t call = {
.request = blocking_request,
.request_length = (uint32_t)sizeof(blocking_request),
.tagged = true,
.completed = &request_thread_completed,
.status = CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR,
};
cbm_thread_t request_thread;
int request_thread_create_rc = -1;
int request_thread_join_rc = -1;
bool request_thread_join_attempted = false;
bool token_reserved = false;
bool request_thread_started = false;
bool callback_started = false;
cbm_daemon_runtime_cancel_result_t wrong_cancel =
CBM_DAEMON_RUNTIME_CANCEL_ERROR;
int cancels_after_wrong = -1;
cbm_daemon_runtime_cancel_result_t exact_cancel =
CBM_DAEMON_RUNTIME_CANCEL_ERROR;
bool cancel_delivered = false;
cbm_daemon_runtime_cancel_result_t late_duplicate_cancel =
CBM_DAEMON_RUNTIME_CANCEL_ERROR;
int cancels_after_duplicate = -1;
bool close_begun = false;
bool request_thread_joined = false;
uint8_t *next_response = NULL;
uint32_t next_response_length = 0;
cbm_daemon_runtime_application_status_t next_status =
CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR;
bool next_exact = false;
bool heartbeat = false;
bool closed = false;
bool exited = false;
if (started) {
client = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS, &result);
}
if (client) {
token_reserved = cbm_daemon_runtime_client_application_token_reserve(
client, &request_token);
}
if (token_reserved) {
call.client = client;
call.request_token = request_token;
request_thread_create_rc = cbm_thread_create(
&request_thread, 128U * 1024U,
runtime_application_client_request_thread, &call);
request_thread_started = request_thread_create_rc == 0;
if (!request_thread_started) {
printf(" runtime helper thread create failed: rc=%d\n",
request_thread_create_rc);
}
callback_started = request_thread_started &&
runtime_test_wait_atomic_bool(
&context.first_request_started,
RUNTIME_TEST_TIMEOUT_MS);
}
if (callback_started) {
wrong_cancel = cbm_daemon_runtime_client_application_cancel(
client, request_token + 1U);
cancels_after_wrong = atomic_load_explicit(
&context.request_cancels, memory_order_acquire);
exact_cancel = cbm_daemon_runtime_client_application_cancel(
client, request_token);
cancel_delivered =
exact_cancel == CBM_DAEMON_RUNTIME_CANCEL_ACCEPTED &&
runtime_test_wait_atomic_int(&context.request_cancels, 1,
RUNTIME_TEST_TIMEOUT_MS);
}
if (request_thread_started && !cancel_delivered && client) {
close_begun = cbm_daemon_runtime_client_close_begin(client);
}
if (request_thread_started && (cancel_delivered || close_begun)) {
request_thread_join_attempted = true;
request_thread_join_rc = cbm_thread_join(&request_thread);
request_thread_joined = request_thread_join_rc == 0;
if (request_thread_joined) {
request_thread_started = false;
} else {
printf(" runtime helper thread join failed: rc=%d\n",
request_thread_join_rc);
}
}
if (request_thread_joined && cancel_delivered && !close_begun) {
late_duplicate_cancel =
cbm_daemon_runtime_client_application_cancel(client,
request_token);
cancels_after_duplicate = atomic_load_explicit(
&context.request_cancels, memory_order_acquire);
next_status = cbm_daemon_runtime_client_application_request(
client, next_request, (uint32_t)sizeof(next_request),
&next_response, &next_response_length,
RUNTIME_TEST_TIMEOUT_MS);
next_exact = next_status == CBM_DAEMON_RUNTIME_APPLICATION_OK &&
next_response_length == sizeof(next_request) &&
next_response &&
memcmp(next_response, next_request,
sizeof(next_request)) == 0;
heartbeat = cbm_daemon_runtime_client_heartbeat(
client, RUNTIME_TEST_TIMEOUT_MS);
}
free(next_response);
if (request_thread_started) {
/* Keep call/client storage alive until the helper's final release
* store even when an exceptional OS join failure prevents proving
* termination through the thread API. */
while (!atomic_load_explicit(&request_thread_completed,
memory_order_acquire)) {
struct timespec pause = {.tv_sec = 0, .tv_nsec = 1000000};
(void)cbm_nanosleep(&pause, NULL);
}
if (!request_thread_join_attempted) {
request_thread_join_attempted = true;
request_thread_join_rc = cbm_thread_join(&request_thread);
request_thread_joined = request_thread_join_rc == 0;
if (request_thread_joined) {
request_thread_started = false;
} else {
printf(" runtime helper thread join failed: rc=%d\n",
request_thread_join_rc);
}
}
}
if (client) {
closed = close_begun
? cbm_daemon_runtime_client_close_finish(
client, RUNTIME_TEST_TIMEOUT_MS)
: cbm_daemon_runtime_client_close(
client, RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
}
if (started) {
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
bool cancelled_response =
call.status == CBM_DAEMON_RUNTIME_APPLICATION_CANCELLED &&
call.response == NULL && call.response_length == 0;
free(call.response);
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(token_reserved);
ASSERT_EQ(request_thread_create_rc, 0);
ASSERT_TRUE(request_thread_join_attempted);
ASSERT_EQ(request_thread_join_rc, 0);
ASSERT_TRUE(callback_started);
ASSERT_EQ(wrong_cancel, CBM_DAEMON_RUNTIME_CANCEL_STALE);
ASSERT_EQ(cancels_after_wrong, 0);
ASSERT_EQ(exact_cancel, CBM_DAEMON_RUNTIME_CANCEL_ACCEPTED);
ASSERT_TRUE(cancel_delivered);
ASSERT_TRUE(request_thread_joined);
ASSERT_TRUE(cancelled_response);
ASSERT_EQ(late_duplicate_cancel, CBM_DAEMON_RUNTIME_CANCEL_STALE);
ASSERT_EQ(cancels_after_duplicate, 1);
ASSERT_TRUE(next_exact);
ASSERT_TRUE(heartbeat);
ASSERT_TRUE(closed);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.opened), 1);
ASSERT_EQ(atomic_load(&context.requests), 2);
ASSERT_EQ(atomic_load(&context.request_cancels), 1);
ASSERT_EQ(atomic_load(&context.cancelled), 1);
ASSERT_EQ(atomic_load(&context.closed), 1);
PASS();
}
TEST(daemon_runtime_presend_request_cancel_is_sticky_and_nonterminal) {
static const uint8_t blocking_request[] = {'p', 'r', 'e'};
static const uint8_t next_request[] = {'n', 'e', 'x', 't'};
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, true);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-presend-cancel", &identity, &context);
cbm_daemon_runtime_connect_result_t result = {0};
cbm_daemon_runtime_client_t *client = NULL;
cbm_daemon_runtime_application_token_t request_token =
CBM_DAEMON_RUNTIME_APPLICATION_TOKEN_INVALID;
bool token_reserved = false;
cbm_daemon_runtime_cancel_result_t cancel =
CBM_DAEMON_RUNTIME_CANCEL_ERROR;
uint8_t *cancelled_response = NULL;
uint32_t cancelled_response_length = 0;
cbm_daemon_runtime_application_status_t cancelled_status =
CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR;
uint8_t *next_response = NULL;
uint32_t next_response_length = 0;
cbm_daemon_runtime_application_status_t next_status =
CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR;
bool next_exact = false;
bool closed = false;
bool exited = false;
if (started) {
client = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS, &result);
}
if (client) {
token_reserved = cbm_daemon_runtime_client_application_token_reserve(
client, &request_token);
}
if (token_reserved) {
cancel = cbm_daemon_runtime_client_application_cancel(
client, request_token);
cancelled_status =
cbm_daemon_runtime_client_application_request_tagged(
client, request_token, blocking_request,
(uint32_t)sizeof(blocking_request), &cancelled_response,
&cancelled_response_length, RUNTIME_TEST_TIMEOUT_MS);
}
if (cancelled_status == CBM_DAEMON_RUNTIME_APPLICATION_CANCELLED) {
next_status = cbm_daemon_runtime_client_application_request(
client, next_request, (uint32_t)sizeof(next_request),
&next_response, &next_response_length,
RUNTIME_TEST_TIMEOUT_MS);
next_exact = next_status == CBM_DAEMON_RUNTIME_APPLICATION_OK &&
next_response_length == sizeof(next_request) &&
next_response &&
memcmp(next_response, next_request,
sizeof(next_request)) == 0;
}
free(cancelled_response);
free(next_response);
if (client) {
closed = cbm_daemon_runtime_client_close(
client, RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
}
if (started) {
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(token_reserved);
ASSERT_EQ(cancel, CBM_DAEMON_RUNTIME_CANCEL_ACCEPTED);
ASSERT_EQ(cancelled_status, CBM_DAEMON_RUNTIME_APPLICATION_CANCELLED);
ASSERT_EQ(cancelled_response_length, 0);
ASSERT_TRUE(next_exact);
ASSERT_TRUE(closed);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.opened), 1);
ASSERT_EQ(atomic_load(&context.requests), 2);
ASSERT_EQ(atomic_load(&context.request_cancels), 1);
ASSERT_EQ(atomic_load(&context.cancelled), 1);
ASSERT_EQ(atomic_load(&context.closed), 1);
PASS();
}
TEST(daemon_runtime_allows_only_one_unstarted_application_token) {
static const uint8_t first_request[] = {'f', 'i', 'r', 's', 't'};
static const uint8_t second_request[] = {'s', 'e', 'c', 'o', 'n', 'd'};
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, false);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-token-reservation", &identity, &context);
cbm_daemon_runtime_connect_result_t result = {0};
cbm_daemon_runtime_client_t *client = NULL;
cbm_daemon_runtime_application_token_t first_token =
CBM_DAEMON_RUNTIME_APPLICATION_TOKEN_INVALID;
cbm_daemon_runtime_application_token_t rejected_token = UINT64_MAX;
cbm_daemon_runtime_application_token_t second_token =
CBM_DAEMON_RUNTIME_APPLICATION_TOKEN_INVALID;
bool first_reserved = false;
bool duplicate_reservation_rejected = false;
bool first_exact = false;
bool second_reserved = false;
bool second_exact = false;
bool closed = false;
bool exited = false;
if (started) {
client = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS, &result);
}
if (client) {
first_reserved = cbm_daemon_runtime_client_application_token_reserve(
client, &first_token);
duplicate_reservation_rejected =
!cbm_daemon_runtime_client_application_token_reserve(
client, &rejected_token) &&
rejected_token == CBM_DAEMON_RUNTIME_APPLICATION_TOKEN_INVALID;
}
if (first_reserved && duplicate_reservation_rejected) {
uint8_t *response = NULL;
uint32_t response_length = 0;
cbm_daemon_runtime_application_status_t status =
cbm_daemon_runtime_client_application_request_tagged(
client, first_token, first_request,
(uint32_t)sizeof(first_request), &response, &response_length,
RUNTIME_TEST_TIMEOUT_MS);
first_exact = status == CBM_DAEMON_RUNTIME_APPLICATION_OK &&
response_length == sizeof(first_request) && response &&
memcmp(response, first_request, sizeof(first_request)) ==
0;
free(response);
}
if (first_exact) {
second_reserved = cbm_daemon_runtime_client_application_token_reserve(
client, &second_token);
}
if (second_reserved) {
uint8_t *response = NULL;
uint32_t response_length = 0;
cbm_daemon_runtime_application_status_t status =
cbm_daemon_runtime_client_application_request_tagged(
client, second_token, second_request,
(uint32_t)sizeof(second_request), &response, &response_length,
RUNTIME_TEST_TIMEOUT_MS);
second_exact = status == CBM_DAEMON_RUNTIME_APPLICATION_OK &&
response_length == sizeof(second_request) && response &&
memcmp(response, second_request,
sizeof(second_request)) == 0;
free(response);
}
if (client) {
closed = cbm_daemon_runtime_client_close(
client, RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
}
if (started) {
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(first_reserved);
ASSERT_TRUE(duplicate_reservation_rejected);
ASSERT_TRUE(first_exact);
ASSERT_TRUE(second_reserved);
ASSERT_EQ(second_token, first_token + 1U);
ASSERT_TRUE(second_exact);
ASSERT_TRUE(closed);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.requests), 2);
PASS();
}
TEST(daemon_runtime_consumes_busy_application_token_before_response) {
static const uint8_t blocking_request[] = {'b', 'l', 'o', 'c', 'k'};
static const uint8_t busy_request[] = {'b', 'u', 's', 'y'};
enum { FIRST_TOKEN = 41, BUSY_TOKEN = 42 };
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, true);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-token-replay", &identity, &context);
cbm_daemon_ipc_connection_t *raw = NULL;
bool first_sent = false;
bool first_started = false;
bool busy_sent = false;
bool busy_received = false;
bool cancel_sent = false;
bool cancellation_received = false;
bool replay_sent = false;
bool replay_rejected = false;
bool exited = false;
if (started) {
raw = runtime_test_raw_client_connect(fixture.endpoint, &identity);
}
if (raw) {
first_sent = runtime_test_raw_application_send_token(
raw, FIRST_TOKEN, blocking_request,
(uint32_t)sizeof(blocking_request),
(uint32_t)sizeof(blocking_request));
first_started = first_sent && runtime_test_wait_atomic_bool(
&context.first_request_started,
RUNTIME_TEST_TIMEOUT_MS);
}
if (first_started) {
busy_sent = runtime_test_raw_application_send_token(
raw, BUSY_TOKEN, busy_request, (uint32_t)sizeof(busy_request),
(uint32_t)sizeof(busy_request));
busy_received =
busy_sent && runtime_test_raw_application_receive_status_token(
raw, BUSY_TOKEN,
CBM_DAEMON_RUNTIME_APPLICATION_BUSY);
}
if (busy_received) {
cancel_sent = runtime_test_raw_application_cancel(raw, FIRST_TOKEN);
cancellation_received =
cancel_sent && runtime_test_raw_application_receive_status_token(
raw, FIRST_TOKEN,
CBM_DAEMON_RUNTIME_APPLICATION_CANCELLED);
}
if (cancellation_received) {
replay_sent = runtime_test_raw_application_send_token(
raw, BUSY_TOKEN, busy_request, (uint32_t)sizeof(busy_request),
(uint32_t)sizeof(busy_request));
}
if (replay_sent) {
cbm_daemon_frame_t frame = {0};
uint8_t *payload = NULL;
int received = cbm_daemon_ipc_receive_frame(
raw, RUNTIME_TEST_TIMEOUT_MS, &frame, &payload);
replay_rejected = received != 1;
free(payload);
}
cbm_daemon_ipc_connection_close(raw);
raw = NULL;
if (started) {
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(first_sent);
ASSERT_TRUE(first_started);
ASSERT_TRUE(busy_sent);
ASSERT_TRUE(busy_received);
ASSERT_TRUE(cancel_sent);
ASSERT_TRUE(cancellation_received);
ASSERT_TRUE(replay_sent);
ASSERT_TRUE(replay_rejected);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.requests), 1);
ASSERT_EQ(atomic_load(&context.request_cancels), 1);
PASS();
}
TEST(daemon_runtime_close_begin_retains_storage_and_rejects_late_exchange) {
static const uint8_t request[] = {'t', 'o', 'o', '-', 'l', 'a', 't', 'e'};
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, false);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-close-gap", &identity, &context);
cbm_daemon_runtime_connect_result_t result = {0};
cbm_daemon_runtime_client_t *client = NULL;
uint8_t *response = NULL;
uint32_t response_length = 0;
cbm_daemon_runtime_application_status_t status =
CBM_DAEMON_RUNTIME_APPLICATION_OK;
bool close_begun = false;
bool duplicate_begin_rejected = false;
bool close_acknowledged = false;
bool exited = false;
if (started) {
client = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS, &result);
}
if (client) {
close_begun = cbm_daemon_runtime_client_close_begin(client);
duplicate_begin_rejected =
close_begun && !cbm_daemon_runtime_client_close_begin(client);
}
if (close_begun) {
/* Deterministically models the frontend boundary where close begins
* after a worker claims an item but before it enters the runtime API.
* The retained allocation must reject the call without touching IPC. */
status = cbm_daemon_runtime_client_application_request(
client, request, (uint32_t)sizeof(request), &response,
&response_length, RUNTIME_TEST_TIMEOUT_MS);
close_acknowledged = cbm_daemon_runtime_client_close_finish(
client, RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
free(response);
if (client) {
if (close_begun) {
(void)cbm_daemon_runtime_client_close_finish(
client, RUNTIME_TEST_TIMEOUT_MS);
} else {
(void)cbm_daemon_runtime_client_close(client,
RUNTIME_TEST_TIMEOUT_MS);
}
}
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(close_begun);
ASSERT_TRUE(duplicate_begin_rejected);
ASSERT_EQ(status, CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR);
ASSERT_NULL(response);
ASSERT_EQ(response_length, 0);
ASSERT_TRUE(close_acknowledged);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.opened), 1);
ASSERT_EQ(atomic_load(&context.requests), 0);
ASSERT_EQ(atomic_load(&context.cancelled), 1);
ASSERT_EQ(atomic_load(&context.closed), 1);
PASS();
}
TEST(daemon_runtime_disconnect_cancels_blocked_application_before_exit) {
static const uint8_t request[] = {'b', 'l', 'o', 'c', 'k'};
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, true);
atomic_bool request_thread_completed;
atomic_init(&request_thread_completed, false);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-cancel", &identity, &context);
cbm_daemon_runtime_client_t *client = NULL;
cbm_daemon_runtime_connect_result_t result = {0};
runtime_application_client_call_t call = {
.request = request,
.request_length = (uint32_t)sizeof(request),
.completed = &request_thread_completed,
.status = CBM_DAEMON_RUNTIME_APPLICATION_OK,
};
cbm_thread_t request_thread;
int request_thread_create_rc = -1;
int request_thread_join_rc = -1;
bool request_thread_join_attempted = false;
bool request_thread_started = false;
bool callback_started = false;
bool close_begun = false;
bool close_acknowledged = false;
bool request_thread_joined = false;
bool request_interrupted = false;
bool exited = false;
if (started) {
client = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS,
&result);
}
if (client) {
call.client = client;
request_thread_create_rc = cbm_thread_create(
&request_thread, 128U * 1024U,
runtime_application_client_request_thread, &call);
request_thread_started = request_thread_create_rc == 0;
if (!request_thread_started) {
printf(" runtime helper thread create failed: rc=%d\n",
request_thread_create_rc);
}
callback_started = request_thread_started &&
runtime_test_wait_atomic_bool(
&context.first_request_started,
RUNTIME_TEST_TIMEOUT_MS);
}
if (callback_started) {
close_begun = cbm_daemon_runtime_client_close_begin(client);
}
if (client && request_thread_started && !close_begun) {
close_begun = cbm_daemon_runtime_client_close_begin(client);
}
if (request_thread_started && close_begun) {
request_thread_join_attempted = true;
request_thread_join_rc = cbm_thread_join(&request_thread);
request_thread_joined = request_thread_join_rc == 0;
if (request_thread_joined) {
request_thread_started = false;
} else {
printf(" runtime helper thread join failed: rc=%d\n",
request_thread_join_rc);
}
}
if (request_thread_started) {
/* A join error does not prove the helper stopped. Wait for its final
* release-store before touching call/client/fixture state. This is
* intentionally unbounded, matching the successful join path's
* semantics while keeping an exceptional cleanup path free of UAF. */
while (!atomic_load_explicit(&request_thread_completed,
memory_order_acquire)) {
struct timespec pause = {.tv_sec = 0, .tv_nsec = 1000000};
(void)cbm_nanosleep(&pause, NULL);
}
if (!request_thread_join_attempted) {
request_thread_join_attempted = true;
request_thread_join_rc = cbm_thread_join(&request_thread);
request_thread_joined = request_thread_join_rc == 0;
if (request_thread_joined) {
request_thread_started = false;
} else {
printf(" runtime helper thread join failed: rc=%d\n",
request_thread_join_rc);
}
}
}
if (client) {
close_acknowledged = close_begun
? cbm_daemon_runtime_client_close_finish(
client, RUNTIME_TEST_TIMEOUT_MS)
: cbm_daemon_runtime_client_close(
client, RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
}
if (started) {
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
request_interrupted =
call.status == CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR &&
call.response == NULL && call.response_length == 0;
free(call.response);
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_EQ(request_thread_create_rc, 0);
ASSERT_TRUE(request_thread_join_attempted);
ASSERT_EQ(request_thread_join_rc, 0);
ASSERT_TRUE(request_thread_joined);
ASSERT_TRUE(callback_started);
ASSERT_TRUE(close_begun);
/* close_begin intentionally interrupted the in-flight transport, so the
* two-phase close cannot also receive a DISCONNECT acknowledgement. EOF
* still closes the server session and must cancel the request/tree. */
ASSERT_FALSE(close_acknowledged);
ASSERT_TRUE(request_interrupted);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.opened), 1);
ASSERT_EQ(atomic_load(&context.requests), 1);
ASSERT_EQ(atomic_load(&context.cancelled), 1);
ASSERT_EQ(atomic_load(&context.closed), 1);
PASS();
}
TEST(daemon_runtime_noncooperative_callback_does_not_detach_or_unbound_stop) {
static const uint8_t request[] = {'i', 'g', 'n', 'o', 'r', 'e'};
enum { STOP_BOUND_MS = 50, STOP_OBSERVED_MAX_MS = 500 };
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, true);
atomic_store_explicit(&context.ignore_first_request_cancel, true,
memory_order_release);
atomic_bool request_thread_completed;
atomic_init(&request_thread_completed, false);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-noncooperative", &identity, &context);
cbm_daemon_runtime_connect_result_t result = {0};
cbm_daemon_runtime_client_t *client = NULL;
runtime_application_client_call_t call = {
.request = request,
.request_length = (uint32_t)sizeof(request),
.completed = &request_thread_completed,
.status = CBM_DAEMON_RUNTIME_APPLICATION_OK,
};
cbm_thread_t request_thread;
int request_thread_create_rc = -1;
int request_thread_join_rc = -1;
bool request_thread_started = false;
bool callback_started = false;
bool close_begun = false;
bool stop_returned = true;
uint64_t stop_elapsed_ms = UINT64_MAX;
bool exited_before_release = false;
bool close_finished = false;
bool exited_after_release = false;
if (started) {
client = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS, &result);
}
if (client) {
call.client = client;
request_thread_create_rc = cbm_thread_create(
&request_thread, 128U * 1024U,
runtime_application_client_request_thread, &call);
request_thread_started = request_thread_create_rc == 0;
callback_started = request_thread_started &&
runtime_test_wait_atomic_bool(
&context.first_request_started,
RUNTIME_TEST_TIMEOUT_MS);
}
if (callback_started) {
close_begun = cbm_daemon_runtime_client_close_begin(client);
uint64_t stop_started_ms = cbm_now_ms();
stop_returned = cbm_daemon_runtime_service_stop(
fixture.service, STOP_BOUND_MS);
stop_elapsed_ms = cbm_now_ms() - stop_started_ms;
exited_before_release =
cbm_daemon_runtime_service_state(fixture.service) ==
CBM_DAEMON_RUNTIME_SERVICE_EXITED;
}
/* A bounded stop failure retains every callback/session allocation. The
* test supplies eventual cooperation so the runner can prove clean join
* and teardown after observing the production host's force boundary. */
atomic_store_explicit(&context.release_first_request, true,
memory_order_release);
if (request_thread_started) {
request_thread_join_rc = cbm_thread_join(&request_thread);
if (request_thread_join_rc == 0) {
request_thread_started = false;
}
}
if (request_thread_started) {
while (!atomic_load_explicit(&request_thread_completed,
memory_order_acquire)) {
struct timespec pause = {.tv_sec = 0, .tv_nsec = 1000000};
(void)cbm_nanosleep(&pause, NULL);
}
}
if (client) {
close_finished = close_begun
? cbm_daemon_runtime_client_close_finish(
client, RUNTIME_TEST_TIMEOUT_MS)
: cbm_daemon_runtime_client_close(
client, RUNTIME_TEST_TIMEOUT_MS);
client = NULL;
}
if (started) {
exited_after_release = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
free(call.response);
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_EQ(result.status, CBM_DAEMON_RUNTIME_CONNECT_ACCEPTED);
ASSERT_EQ(request_thread_create_rc, 0);
ASSERT_TRUE(callback_started);
ASSERT_TRUE(close_begun);
ASSERT_FALSE(stop_returned);
ASSERT_TRUE(stop_elapsed_ms <= STOP_OBSERVED_MAX_MS);
ASSERT_FALSE(exited_before_release);
ASSERT_EQ(request_thread_join_rc, 0);
/* The interrupted transport cannot receive a final disconnect ACK. */
ASSERT_FALSE(close_finished);
ASSERT_TRUE(exited_after_release);
ASSERT_EQ(atomic_load(&context.opened), 1);
ASSERT_EQ(atomic_load(&context.requests), 1);
ASSERT_EQ(atomic_load(&context.cancelled), 1);
ASSERT_EQ(atomic_load(&context.closed), 1);
PASS();
}
TEST(daemon_runtime_application_busy_cap_and_malformed_are_isolated) {
static const uint8_t blocking_request[] = {'f', 'i', 'r', 's', 't'};
static const uint8_t busy_request[] = {'b', 'u', 's', 'y'};
static const uint8_t malformed_request[] = {'x', 'y'};
static const uint8_t valid_request[] = {0xde, 0xad, 0x00, 0xbe, 0xef};
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, true);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-isolation", &identity, &context);
cbm_daemon_runtime_client_t *owner = NULL;
cbm_daemon_runtime_connect_result_t owner_result = {0};
cbm_daemon_ipc_connection_t *raw = NULL;
bool first_sent = false;
bool callback_started = false;
bool busy_sent = false;
bool busy_rejected = false;
bool malformed_sent = false;
bool bad_peer_released = false;
uint8_t sentinel = 0x5a;
uint8_t *oversize_response = (uint8_t *)&sentinel;
uint32_t oversize_response_length = UINT32_MAX;
cbm_daemon_runtime_application_status_t oversize_status =
CBM_DAEMON_RUNTIME_APPLICATION_OK;
uint8_t *valid_response = NULL;
uint32_t valid_response_length = 0;
cbm_daemon_runtime_application_status_t valid_status =
CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR;
bool owner_survived = false;
bool exited = false;
if (started) {
owner = cbm_daemon_runtime_client_connect(fixture.endpoint, &identity,
RUNTIME_TEST_TIMEOUT_MS,
&owner_result);
raw = runtime_test_raw_client_connect(fixture.endpoint, &identity);
}
if (owner && raw) {
first_sent = runtime_test_raw_application_send(
raw, blocking_request, (uint32_t)sizeof(blocking_request),
(uint32_t)sizeof(blocking_request));
callback_started = first_sent && runtime_test_wait_atomic_bool(
&context.first_request_started,
RUNTIME_TEST_TIMEOUT_MS);
}
if (callback_started) {
busy_sent = runtime_test_raw_application_send(
raw, busy_request, (uint32_t)sizeof(busy_request),
(uint32_t)sizeof(busy_request));
busy_rejected = busy_sent &&
runtime_test_raw_application_receive_status(
raw, CBM_DAEMON_RUNTIME_APPLICATION_BUSY);
}
if (busy_rejected) {
malformed_sent = runtime_test_raw_application_send(
raw, malformed_request, (uint32_t)sizeof(malformed_request),
(uint32_t)sizeof(malformed_request) + 1U);
}
cbm_daemon_ipc_connection_close(raw);
raw = NULL;
if (malformed_sent) {
bad_peer_released = cbm_daemon_runtime_service_wait_for_clients(
fixture.service, 1, RUNTIME_TEST_TIMEOUT_MS);
}
if (owner && bad_peer_released) {
oversize_status = cbm_daemon_runtime_client_application_request(
owner, &sentinel,
CBM_DAEMON_RUNTIME_APPLICATION_PAYLOAD_MAX + 1U,
&oversize_response, &oversize_response_length,
RUNTIME_TEST_TIMEOUT_MS);
valid_status = cbm_daemon_runtime_client_application_request(
owner, valid_request, (uint32_t)sizeof(valid_request),
&valid_response, &valid_response_length,
RUNTIME_TEST_TIMEOUT_MS);
owner_survived =
oversize_status ==
CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR &&
oversize_response == NULL && oversize_response_length == 0 &&
valid_status == CBM_DAEMON_RUNTIME_APPLICATION_OK &&
valid_response_length == sizeof(valid_request) && valid_response &&
memcmp(valid_response, valid_request, sizeof(valid_request)) == 0 &&
cbm_daemon_runtime_client_heartbeat(owner,
RUNTIME_TEST_TIMEOUT_MS);
free(valid_response);
valid_response = NULL;
(void)cbm_daemon_runtime_client_close(owner,
RUNTIME_TEST_TIMEOUT_MS);
owner = NULL;
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
free(valid_response);
if (owner) {
(void)cbm_daemon_runtime_client_close(owner,
RUNTIME_TEST_TIMEOUT_MS);
}
cbm_daemon_ipc_connection_close(raw);
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(first_sent);
ASSERT_TRUE(callback_started);
ASSERT_TRUE(busy_sent);
ASSERT_TRUE(busy_rejected);
ASSERT_TRUE(malformed_sent);
ASSERT_TRUE(bad_peer_released);
ASSERT_TRUE(owner_survived);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.opened), 2);
ASSERT_EQ(atomic_load(&context.requests), 2);
ASSERT_EQ(atomic_load(&context.cancelled), 2);
ASSERT_EQ(atomic_load(&context.closed), 2);
PASS();
}
TEST(daemon_runtime_malformed_and_zero_cancel_close_only_offending_connections) {
static const uint8_t valid_request[] = {'s', 'u', 'r', 'v', 'i', 'v', 'e'};
static const uint8_t malformed_cancel[7] = {1};
static const uint8_t zero_token_cancel[8] = {0};
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_application_context_t context;
runtime_application_context_init(&context, false);
runtime_test_fixture_t fixture;
bool started = runtime_test_fixture_start_application(
&fixture, "application-cancel-isolation", &identity, &context);
cbm_daemon_runtime_connect_result_t owner_result = {0};
cbm_daemon_runtime_client_t *owner = NULL;
cbm_daemon_ipc_connection_t *raw = NULL;
bool malformed_connected = false;
bool malformed_sent = false;
bool malformed_released = false;
bool malformed_closed = false;
bool zero_connected = false;
bool zero_sent = false;
bool zero_released = false;
bool zero_closed = false;
uint8_t *valid_response = NULL;
uint32_t valid_response_length = 0;
cbm_daemon_runtime_application_status_t valid_status =
CBM_DAEMON_RUNTIME_APPLICATION_TRANSPORT_ERROR;
bool owner_survived = false;
bool owner_closed = false;
bool exited = false;
if (started) {
owner = cbm_daemon_runtime_client_connect(
fixture.endpoint, &identity, RUNTIME_TEST_TIMEOUT_MS,
&owner_result);
}
if (owner) {
raw = runtime_test_raw_client_connect(fixture.endpoint, &identity);
malformed_connected = raw != NULL;
}
if (raw) {
malformed_sent = cbm_daemon_ipc_send_frame(
raw, CBM_DAEMON_FRAME_REQUEST,
CBM_DAEMON_RUNTIME_OP_APPLICATION_CANCEL, malformed_cancel,
(uint32_t)sizeof(malformed_cancel));
}
if (malformed_sent) {
malformed_released = cbm_daemon_runtime_service_wait_for_clients(
fixture.service, 1, RUNTIME_TEST_TIMEOUT_MS);
}
if (malformed_released) {
cbm_daemon_frame_t frame = {0};
uint8_t *payload = NULL;
int received = cbm_daemon_ipc_receive_frame(
raw, RUNTIME_TEST_TIMEOUT_MS, &frame, &payload);
malformed_closed = received != 1;
free(payload);
}
cbm_daemon_ipc_connection_close(raw);
raw = NULL;
if (owner && malformed_closed) {
raw = runtime_test_raw_client_connect(fixture.endpoint, &identity);
zero_connected = raw != NULL;
}
if (raw) {
zero_sent = cbm_daemon_ipc_send_frame(
raw, CBM_DAEMON_FRAME_REQUEST,
CBM_DAEMON_RUNTIME_OP_APPLICATION_CANCEL, zero_token_cancel,
(uint32_t)sizeof(zero_token_cancel));
}
if (zero_sent) {
zero_released = cbm_daemon_runtime_service_wait_for_clients(
fixture.service, 1, RUNTIME_TEST_TIMEOUT_MS);
}
if (zero_released) {
cbm_daemon_frame_t frame = {0};
uint8_t *payload = NULL;
int received = cbm_daemon_ipc_receive_frame(
raw, RUNTIME_TEST_TIMEOUT_MS, &frame, &payload);
zero_closed = received != 1;
free(payload);
}
cbm_daemon_ipc_connection_close(raw);
raw = NULL;
if (owner && zero_closed) {
valid_status = cbm_daemon_runtime_client_application_request(
owner, valid_request, (uint32_t)sizeof(valid_request),
&valid_response, &valid_response_length,
RUNTIME_TEST_TIMEOUT_MS);
owner_survived =
valid_status == CBM_DAEMON_RUNTIME_APPLICATION_OK &&
valid_response_length == sizeof(valid_request) && valid_response &&
memcmp(valid_response, valid_request, sizeof(valid_request)) == 0 &&
cbm_daemon_runtime_client_heartbeat(owner,
RUNTIME_TEST_TIMEOUT_MS);
}
free(valid_response);
if (owner) {
owner_closed = cbm_daemon_runtime_client_close(
owner, RUNTIME_TEST_TIMEOUT_MS);
owner = NULL;
}
if (started) {
exited = cbm_daemon_runtime_service_wait_exited(
fixture.service, RUNTIME_TEST_TIMEOUT_MS);
}
cbm_daemon_ipc_connection_close(raw);
runtime_test_fixture_finish(&fixture);
ASSERT_TRUE(started);
ASSERT_TRUE(malformed_connected);
ASSERT_TRUE(malformed_sent);
ASSERT_TRUE(malformed_released);
ASSERT_TRUE(malformed_closed);
ASSERT_TRUE(zero_connected);
ASSERT_TRUE(zero_sent);
ASSERT_TRUE(zero_released);
ASSERT_TRUE(zero_closed);
ASSERT_TRUE(owner_survived);
ASSERT_TRUE(owner_closed);
ASSERT_TRUE(exited);
ASSERT_EQ(atomic_load(&context.opened), 3);
ASSERT_EQ(atomic_load(&context.requests), 1);
ASSERT_EQ(atomic_load(&context.request_cancels), 0);
ASSERT_EQ(atomic_load(&context.cancelled), 3);
ASSERT_EQ(atomic_load(&context.closed), 3);
PASS();
}
TEST(daemon_runtime_kernel_process_fingerprint_is_stable_and_fail_closed) {
char first[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
char repeated[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
char invalid[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
bool first_ok = cbm_daemon_runtime_process_build_fingerprint(
runtime_test_process_id(), first);
bool repeated_ok = cbm_daemon_runtime_process_build_fingerprint(
runtime_test_process_id(), repeated);
bool invalid_rejected = !cbm_daemon_runtime_process_build_fingerprint(
UINT64_MAX, invalid);
ASSERT_TRUE(first_ok);
ASSERT_TRUE(repeated_ok);
ASSERT_TRUE(runtime_test_is_fingerprint(first));
ASSERT_STR_EQ(first, repeated);
ASSERT_TRUE(invalid_rejected);
ASSERT_STR_EQ(invalid, "");
PASS();
}
#ifdef __APPLE__
/* RED: the former macOS fast path accepted the daemon vnode in any RX mapping,
* even when a differently fingerprinted main executable owned the connection.
* Re-signing the changed copy keeps the probe runnable on arm64 while ensuring
* that only the deliberately injected mapping has the active identity. */
TEST(daemon_runtime_mac_fast_path_rejects_foreign_main_image_mapping_active) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
char directory[RUNTIME_TEST_PATH_CAP] = {0};
char active_image[RUNTIME_TEST_PATH_CAP] = {0};
char foreign_image[RUNTIME_TEST_PATH_CAP] = {0};
char foreign_fingerprint[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
int directory_written = snprintf(
directory, sizeof(directory), "%s/cbm-runtime-mapped-image-XXXXXX",
cbm_tmpdir());
bool directory_created =
directory_written > 0 && directory_written < (int)sizeof(directory) &&
cbm_mkdtemp(directory) != NULL;
int foreign_written =
directory_created
? snprintf(foreign_image, sizeof(foreign_image), "%s/foreign-client",
directory)
: -1;
bool active_resolved = runtime_test_self_image_path(active_image);
bool foreign_copied =
active_resolved && foreign_written > 0 &&
foreign_written < (int)sizeof(foreign_image) &&
runtime_test_copy_executable(active_image, foreign_image);
/* A distinct signing identifier changes the Mach-O signature bytes while
* keeping the copied executable valid under macOS strict validation. */
bool foreign_changed = foreign_copied;
bool foreign_signed =
foreign_changed && runtime_test_mac_ad_hoc_sign(foreign_image);
bool foreign_fingerprinted =
foreign_signed && cbm_daemon_build_fingerprint_file(
foreign_image, foreign_fingerprint);
bool fingerprint_differs =
foreign_fingerprinted &&
strcmp(foreign_fingerprint, identity.build_fingerprint) != 0;
runtime_test_fixture_t fixture;
memset(&fixture, 0, sizeof(fixture));
bool fixture_attempted = directory_created && active_resolved &&
fingerprint_differs;
bool started = fixture_attempted && runtime_test_fixture_start(
&fixture, "mapped-foreign", &identity);
int foreign_exit = -1;
bool foreign_ran =
started && runtime_test_run_mapped_hello_image(
foreign_image, active_image, &fixture, &identity,
&foreign_exit);
if (fixture_attempted) {
runtime_test_fixture_finish(&fixture);
}
if (foreign_written > 0 &&
foreign_written < (int)sizeof(foreign_image)) {
(void)cbm_unlink(foreign_image);
}
if (directory_created) {
(void)cbm_rmdir(directory);
}
ASSERT_TRUE(directory_created);
ASSERT_TRUE(active_resolved);
ASSERT_TRUE(foreign_copied);
ASSERT_TRUE(foreign_changed);
ASSERT_TRUE(foreign_signed);
ASSERT_TRUE(foreign_fingerprinted);
ASSERT_TRUE(fingerprint_differs);
ASSERT_TRUE(started);
ASSERT_TRUE(foreign_ran);
ASSERT_EQ(foreign_exit, 26);
PASS();
}
#endif
TEST(daemon_runtime_copied_image_fallback_accepts_identical_and_rejects_changed) {
cbm_daemon_build_identity_t identity =
runtime_test_identity("2.4.0", runtime_test_self_build());
runtime_test_fixture_t identical_fixture;
bool identical_started = runtime_test_fixture_start(
&identical_fixture, "copied-identical", &identity);
char identical_path[RUNTIME_TEST_PATH_CAP] = {0};
int identical_path_written =
identical_started
#ifdef _WIN32
? snprintf(identical_path, sizeof(identical_path),
"%s/client-copy.exe", identical_fixture.parent)
#else
? snprintf(identical_path, sizeof(identical_path), "%s/client-copy",
identical_fixture.parent)
#endif
: -1;
bool identical_copied = identical_path_written > 0 &&
identical_path_written < (int)sizeof(identical_path) &&
runtime_test_copy_self_image(identical_path);
char identical_fingerprint[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
bool identical_bytes =
identical_copied && cbm_daemon_build_fingerprint_file(
identical_path, identical_fingerprint) &&
strcmp(identical_fingerprint, identity.build_fingerprint) == 0;
int identical_exit = -1;
bool identical_ran = identical_bytes && runtime_test_run_hello_image(
identical_path,
&identical_fixture, &identity,
&identical_exit);
bool identical_exited =
identical_ran && identical_exit == 0 &&
cbm_daemon_runtime_service_wait_exited(
identical_fixture.service, RUNTIME_TEST_TIMEOUT_MS);
(void)cbm_unlink(identical_path);
runtime_test_fixture_finish(&identical_fixture);
#ifdef __linux__
runtime_test_fixture_t changed_fixture;
bool changed_started = runtime_test_fixture_start(
&changed_fixture, "copied-changed", &identity);
char changed_path[RUNTIME_TEST_PATH_CAP] = {0};
int changed_path_written =
changed_started
? snprintf(changed_path, sizeof(changed_path), "%s/client-copy",
changed_fixture.parent)
: -1;
bool changed_copied =
changed_path_written > 0 &&
changed_path_written < (int)sizeof(changed_path) &&
runtime_test_copy_self_image(changed_path) &&
runtime_test_append_image_marker(changed_path);
char changed_fingerprint[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
bool changed_bytes =
changed_copied && cbm_daemon_build_fingerprint_file(
changed_path, changed_fingerprint) &&
strcmp(changed_fingerprint, identity.build_fingerprint) != 0;
int changed_exit = -1;
bool changed_ran = changed_bytes && runtime_test_run_hello_image(
changed_path, &changed_fixture,
&identity, &changed_exit);
(void)cbm_unlink(changed_path);
runtime_test_fixture_finish(&changed_fixture);
#endif
ASSERT_TRUE(identical_started);
ASSERT_TRUE(identical_copied);
ASSERT_TRUE(identical_bytes);
ASSERT_TRUE(identical_ran);
ASSERT_EQ(identical_exit, 0);
ASSERT_TRUE(identical_exited);
#ifdef __linux__
ASSERT_TRUE(changed_started);
ASSERT_TRUE(changed_copied);
ASSERT_TRUE(changed_bytes);
ASSERT_TRUE(changed_ran);
ASSERT_EQ(changed_exit, 26);
#endif
PASS();
}
#ifdef _WIN32
TEST(daemon_runtime_process_fingerprint_never_hashes_replacement_path) {
char directory[RUNTIME_TEST_PATH_CAP] = {0};
char image_path[RUNTIME_TEST_PATH_CAP] = {0};
char replacement_path[RUNTIME_TEST_PATH_CAP] = {0};
char event_name[128] = {0};
int directory_written = snprintf(directory, sizeof(directory),
"%s/cbm-runtime-image-XXXXXX",
cbm_tmpdir());
bool setup = directory_written > 0 &&
directory_written < (int)sizeof(directory) &&
cbm_mkdtemp(directory) != NULL;
int image_written =
setup ? snprintf(image_path, sizeof(image_path), "%s/image.exe",
directory)
: -1;
int replacement_written =
setup ? snprintf(replacement_path, sizeof(replacement_path),
"%s/replacement.exe", directory)
: -1;
int event_written = snprintf(
event_name, sizeof(event_name), "Local\\cbm-runtime-image-%lu-%llu",
(unsigned long)GetCurrentProcessId(),
(unsigned long long)GetTickCount64());
setup = setup && image_written > 0 &&
image_written < (int)sizeof(image_path) &&
replacement_written > 0 &&
replacement_written < (int)sizeof(replacement_path) &&
event_written > 0 && event_written < (int)sizeof(event_name) &&
runtime_test_windows_copy_self(image_path);
FILE *replacement_file = setup ? cbm_fopen(replacement_path, "wb") : NULL;
bool replacement_written_ok =
replacement_file &&
fputs("cbm-windows-replacement-image", replacement_file) >= 0;
if (replacement_file) {
replacement_written_ok = fclose(replacement_file) == 0 &&
replacement_written_ok;
}
setup = setup && replacement_written_ok;
char original[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
char replacement[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
char observed[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
setup = setup && cbm_daemon_build_fingerprint_file(image_path, original) &&
cbm_daemon_build_fingerprint_file(replacement_path, replacement) &&
strcmp(original, replacement) != 0;
HANDLE ready_event =
setup ? CreateEventA(NULL, TRUE, FALSE, event_name) : NULL;
bool event_private = ready_event && GetLastError() != ERROR_ALREADY_EXISTS;
PROCESS_INFORMATION process;
memset(&process, 0, sizeof(process));
bool spawned = event_private && runtime_test_windows_spawn_image_holder(
image_path, event_name, &process);
bool ready = spawned &&
WaitForSingleObject(ready_event, 5000) == WAIT_OBJECT_0;
bool replaced = ready && runtime_test_windows_posix_replace(
replacement_path, image_path);
bool fingerprinted =
ready && cbm_daemon_runtime_process_build_fingerprint(
(uint64_t)process.dwProcessId, observed);
bool replacement_safe =
replaced ? (!fingerprinted || strcmp(observed, original) == 0)
: (fingerprinted && strcmp(observed, original) == 0);
bool stopped = !spawned;
if (spawned) {
DWORD exit_code = 0;
bool running = GetExitCodeProcess(process.hProcess, &exit_code) != 0 &&
exit_code == STILL_ACTIVE;
bool termination_requested =
!running || TerminateProcess(process.hProcess, 26) != 0;
stopped = termination_requested &&
WaitForSingleObject(process.hProcess, 5000) == WAIT_OBJECT_0;
(void)CloseHandle(process.hProcess);
}
if (ready_event) {
(void)CloseHandle(ready_event);
}
(void)cbm_unlink(replacement_path);
(void)cbm_unlink(image_path);
(void)cbm_rmdir(directory);
ASSERT_TRUE(setup);
ASSERT_TRUE(event_private);
ASSERT_TRUE(spawned);
ASSERT_TRUE(ready);
ASSERT_TRUE(stopped);
ASSERT_TRUE(replacement_safe);
ASSERT_TRUE(!fingerprinted || strcmp(observed, replacement) != 0);
PASS();
}
#elif defined(__APPLE__) || defined(__linux__)
TEST(daemon_runtime_process_fingerprint_never_hashes_replacement_path) {
char directory[RUNTIME_TEST_PATH_CAP] = {0};
char image_path[RUNTIME_TEST_PATH_CAP] = {0};
char replacement_path[RUNTIME_TEST_PATH_CAP] = {0};
int directory_written = snprintf(directory, sizeof(directory),
"%s/cbm-runtime-image-XXXXXX",
cbm_tmpdir());
bool setup = directory_written > 0 &&
directory_written < (int)sizeof(directory) &&
cbm_mkdtemp(directory) != NULL;
int image_written = setup
? snprintf(image_path, sizeof(image_path), "%s/image",
directory)
: -1;
int replacement_written = setup
? snprintf(replacement_path,
sizeof(replacement_path),
"%s/replacement", directory)
: -1;
setup = setup && image_written > 0 &&
image_written < (int)sizeof(image_path) &&
replacement_written > 0 &&
replacement_written < (int)sizeof(replacement_path) &&
runtime_test_copy_executable("/bin/cat", image_path) &&
runtime_test_copy_executable("/bin/echo", replacement_path);
char original[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
char replacement[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
char observed[CBM_DAEMON_BUILD_FINGERPRINT_SIZE] = {0};
setup = setup && cbm_daemon_build_fingerprint_file(image_path, original);
int release_fd = -1;
pid_t child = setup
? runtime_test_spawn_blocked_executable(image_path,
&release_fd)
: -1;
setup = setup && child > 0 && rename(replacement_path, image_path) == 0 &&
cbm_daemon_build_fingerprint_file(image_path, replacement) &&
strcmp(original, replacement) != 0;
bool fingerprinted =
setup && cbm_daemon_runtime_process_build_fingerprint((uint64_t)child,
observed);
runtime_test_stop_blocked_executable(child, release_fd);
(void)unlink(replacement_path);
(void)unlink(image_path);
(void)rmdir(directory);
ASSERT_TRUE(setup);
#ifdef __linux__
/* /proc/<pid>/exe is an openable kernel link to the mapped inode, even
* after that inode has been unlinked by the atomic replacement. */
ASSERT_TRUE(fingerprinted);
ASSERT_STR_EQ(observed, original);
#else
/* macOS exposes mapped vnode identity but not a public handle to the
* mapped executable. If the old vnode no longer has an openable path we
* must fail closed; resolving and hashing the new path is forbidden. */
ASSERT_TRUE(!fingerprinted || strcmp(observed, original) == 0);
#endif
ASSERT_TRUE(!fingerprinted || strcmp(observed, replacement) != 0);
PASS();
}
#endif
SUITE(daemon_runtime) {
#ifndef _WIN32
RUN_TEST(daemon_host_failed_listener_reservation_starts_no_background_work);
RUN_TEST(daemon_host_persistent_cleanup_release_failure_is_process_bounded);
RUN_TEST(daemon_host_forced_shutdown_is_logged_flushed_and_process_bounded);
#endif
RUN_TEST(daemon_runtime_kernel_process_fingerprint_is_stable_and_fail_closed);
#ifdef __APPLE__
RUN_TEST(daemon_runtime_mac_fast_path_rejects_foreign_main_image_mapping_active);
#endif
RUN_TEST(daemon_runtime_copied_image_fallback_accepts_identical_and_rejects_changed);
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
RUN_TEST(daemon_runtime_process_fingerprint_never_hashes_replacement_path);
#endif
RUN_TEST(daemon_runtime_convenience_service_owns_participant_guard);
RUN_TEST(daemon_runtime_rendezvous_layout_is_frozen_and_detailed_abi_independent);
RUN_TEST(daemon_runtime_exact_hello_issues_connection_bound_identity);
RUN_TEST(daemon_runtime_activation_rejects_forged_and_malformed_without_stop);
RUN_TEST(daemon_runtime_activation_ack_snapshots_then_interrupts_all_clients);
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
RUN_TEST(daemon_runtime_activation_accepts_authenticated_different_build);
#endif
RUN_TEST(daemon_runtime_future_generation_gets_stable_explicit_conflict);
RUN_TEST(daemon_runtime_matching_clients_share_one_service_endpoint);
RUN_TEST(daemon_runtime_same_version_different_build_is_visible_and_logged);
RUN_TEST(daemon_runtime_conflict_log_failure_uses_operation_log_fallback);
RUN_TEST(daemon_runtime_disconnect_releases_only_connection_subscriptions);
RUN_TEST(daemon_runtime_final_disconnect_automatically_exits_within_bound);
RUN_TEST(daemon_runtime_authenticated_idle_connection_outlives_lease_interval);
RUN_TEST(daemon_runtime_connection_cap_covers_slow_hello_and_stopping_is_terminal);
RUN_TEST(daemon_runtime_rejects_forged_identity_extension);
RUN_TEST(daemon_runtime_application_response_roundtrip_is_byte_exact);
RUN_TEST(daemon_runtime_final_disconnect_rejects_blocked_provisional_session);
RUN_TEST(daemon_runtime_request_cancel_is_exact_and_session_remains_usable);
RUN_TEST(daemon_runtime_presend_request_cancel_is_sticky_and_nonterminal);
RUN_TEST(daemon_runtime_allows_only_one_unstarted_application_token);
RUN_TEST(daemon_runtime_consumes_busy_application_token_before_response);
RUN_TEST(daemon_runtime_close_begin_retains_storage_and_rejects_late_exchange);
RUN_TEST(daemon_runtime_disconnect_cancels_blocked_application_before_exit);
RUN_TEST(daemon_runtime_noncooperative_callback_does_not_detach_or_unbound_stop);
RUN_TEST(daemon_runtime_application_busy_cap_and_malformed_are_isolated);
RUN_TEST(daemon_runtime_malformed_and_zero_cancel_close_only_offending_connections);
}