#include "../src/uds_server.h"
#include <cassert>
#include <cstdio>
#include <cstring>
#include <thread>
#include <chrono>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
static int tests_passed = 0;
#define TEST(name) \
do { \
printf(" %-40s", #name "..."); \
} while (0)
#define PASS() \
do { \
printf("PASS\n"); \
tests_passed++; \
} while (0)
static const char *TEST_SOCK = "/tmp/test_bb_uds.sock";
// Helper: connect a client socket
static int connect_client(const char *path) {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
return -1;
struct sockaddr_un addr = {};
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(fd);
return -1;
}
return fd;
}
// Helper: send a length-prefixed message
static bool send_msg(int fd, const void *data, uint32_t len) {
uint32_t le_len = len; // already LE on x86
if (write(fd, &le_len, 4) != 4)
return false;
if (write(fd, data, len) != (ssize_t)len)
return false;
return true;
}
void test_server_start_stop() {
TEST(server_start_stop);
UdsServer server;
assert(server.start(TEST_SOCK));
assert(server.listening());
server.stop();
assert(!server.listening());
PASS();
}
void test_client_connect() {
TEST(client_connect);
UdsServer server;
assert(server.start(TEST_SOCK));
// Connect a client
int client_fd = connect_client(TEST_SOCK);
assert(client_fd >= 0);
// Poll server to accept
server.poll();
assert(server.client_count() == 1);
close(client_fd);
server.stop();
PASS();
}
void test_message_roundtrip() {
TEST(message_roundtrip);
UdsServer server;
assert(server.start(TEST_SOCK));
int client_fd = connect_client(TEST_SOCK);
assert(client_fd >= 0);
server.poll(); // accept
// Client sends a message
const char *msg = "hello_bridge";
assert(send_msg(client_fd, msg, strlen(msg)));
// Small delay for data to arrive
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// Poll to read
server.poll();
assert(server.has_messages());
UdsMessage received = server.next_message();
assert(received.size == strlen(msg));
assert(memcmp(received.data.data(), msg, strlen(msg)) == 0);
close(client_fd);
server.stop();
PASS();
}
void test_server_send_to_client() {
TEST(server_send_to_client);
UdsServer server;
assert(server.start(TEST_SOCK));
int client_fd = connect_client(TEST_SOCK);
assert(client_fd >= 0);
server.poll(); // accept
// Server sends to all clients
const char *msg = "scene_update";
server.broadcast(msg, strlen(msg));
// Read on client side
std::this_thread::sleep_for(std::chrono::milliseconds(10));
uint32_t len = 0;
assert(read(client_fd, &len, 4) == 4);
assert(len == strlen(msg));
char buf[64] = {};
assert(read(client_fd, buf, len) == (ssize_t)len);
assert(memcmp(buf, msg, len) == 0);
close(client_fd);
server.stop();
PASS();
}
void test_client_disconnect_detection() {
TEST(client_disconnect_detection);
UdsServer server;
assert(server.start(TEST_SOCK));
int client_fd = connect_client(TEST_SOCK);
assert(client_fd >= 0);
server.poll(); // accept
assert(server.client_count() == 1);
// Client disconnects
close(client_fd);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// Poll should detect disconnect
server.poll();
assert(server.client_count() == 0);
server.stop();
PASS();
}
void test_multiple_clients() {
TEST(multiple_clients);
UdsServer server;
assert(server.start(TEST_SOCK));
int c1 = connect_client(TEST_SOCK);
int c2 = connect_client(TEST_SOCK);
assert(c1 >= 0 && c2 >= 0);
server.poll();
assert(server.client_count() == 2);
// Broadcast reaches both
const char *msg = "sync";
server.broadcast(msg, strlen(msg));
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// Read from both clients
for (int fd : {c1, c2}) {
uint32_t len = 0;
assert(read(fd, &len, 4) == 4);
assert(len == 4);
char buf[8] = {};
assert(read(fd, buf, len) == (ssize_t)len);
assert(memcmp(buf, "sync", 4) == 0);
}
close(c1);
close(c2);
server.stop();
PASS();
}
void test_multiple_messages() {
TEST(multiple_messages);
UdsServer server;
assert(server.start(TEST_SOCK));
int client_fd = connect_client(TEST_SOCK);
assert(client_fd >= 0);
server.poll(); // accept
// Send 3 messages back-to-back
for (int i = 0; i < 3; i++) {
char msg[16];
int len = snprintf(msg, sizeof(msg), "msg_%d", i);
assert(send_msg(client_fd, msg, len));
}
std::this_thread::sleep_for(std::chrono::milliseconds(20));
server.poll();
// Should have all 3
for (int i = 0; i < 3; i++) {
assert(server.has_messages());
UdsMessage m = server.next_message();
char expected[16];
int elen = snprintf(expected, sizeof(expected), "msg_%d", i);
assert(m.size == (uint32_t)elen);
assert(memcmp(m.data.data(), expected, elen) == 0);
}
assert(!server.has_messages());
close(client_fd);
server.stop();
PASS();
}
int main() {
printf("=== UDS Server Tests ===\n");
test_server_start_stop();
test_client_connect();
test_message_roundtrip();
test_server_send_to_client();
test_client_disconnect_detection();
test_multiple_clients();
test_multiple_messages();
printf("\nAll %d tests passed.\n", tests_passed);
return 0;
}