diff --git a/tests/Makefile.am b/tests/Makefile.am index 4bb2970d..fde5e1a2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -301,6 +301,7 @@ if OS_LINUX test_socket_monitor_LDFLAGS += -Wl,--wrap=recvfrom -Wl,--wrap=__recvfrom_chk check_PROGRAMS += test_config_parser check_PROGRAMS += test_chat_setting +check_PROGRAMS += test_chat_channel check_PROGRAMS += test_instance_contract test_instance_contract_SOURCES = test_instance_contract.c test_instance_contract_LDADD = $(LIBUTUN) $(COMMON_LIBS) @@ -311,6 +312,9 @@ test_config_parser_LDFLAGS = -Wl,--wrap=u_calloc_impl -Wl,--wrap=u_realloc_impl test_chat_setting_SOURCES = test_chat_setting.c test_chat_setting_LDADD = $(LIBUTUN) $(COMMON_LIBS) test_chat_setting_LDFLAGS = -Wl,--wrap=chat_local_apply_settings +test_chat_channel_SOURCES = test_chat_channel.c +test_chat_channel_LDADD = $(LIBUTUN) $(COMMON_LIBS) +test_chat_channel_LDFLAGS = -Wl,--wrap=EVP_DigestSign else test_socket_monitor_LDFLAGS += -Wl,--wrap=read endif diff --git a/tests/test_chat_channel.c b/tests/test_chat_channel.c new file mode 100644 index 00000000..ed7c4471 --- /dev/null +++ b/tests/test_chat_channel.c @@ -0,0 +1,70 @@ +/* Создание канала: настоящие ключи/подписи/SQLite; отказ не публикует незавершённый канал. */ +#define _GNU_SOURCE +#include +#include +#include +#include "../src/utun_instance.h" +#include "../src/chat/chat_core.h" +#include "../src/chat/chat_core_priv.h" +#include "../src/chat/chat_event.h" +#include "../src/chat/member_sync.h" +#include "../src/routing_layer/topo_node_sqlite.h" +#include "../lib/platform_compat.h" +#include "../lib/debug_config.h" +#include "../lib/mem.h" + +static unsigned fail_sign_number, channel_events; +static sqlite3* reader; + +extern int __real_EVP_DigestSign(EVP_MD_CTX*, unsigned char*, size_t*, const unsigned char*, size_t); +int __wrap_EVP_DigestSign(EVP_MD_CTX* ctx, unsigned char* signature, size_t* length, const unsigned char* data, size_t size) { + if (fail_sign_number && !--fail_sign_number) { + DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "channel test: injected signature failure bytes=%zu", size); return 0; + } + return __real_EVP_DigestSign(ctx, signature, length, data, size); +} + +static int channels(void) { + sqlite3_stmt* st = NULL; + assert(sqlite3_prepare_v2(reader, "SELECT count(*) FROM channels", -1, &st, NULL) == SQLITE_OK && sqlite3_step(st) == SQLITE_ROW); + int count = sqlite3_column_int(st, 0); assert(sqlite3_finalize(st) == SQLITE_OK); return count; +} + +/* Обработчик видит канал и проверенного участника уже после commit. */ +static void event(struct UTUN_INSTANCE* inst, int type, const uint8_t* data, int size) { + if (type != CHAT_EVT_CHANNEL_UPDATED) return; + assert(sqlite3_get_autocommit(inst->topo_sqlite_db) && size == data[0] + 1 && data[0] < 20); + char channel[20]; memcpy(channel, data + 1, data[0]); channel[data[0]] = 0; + sqlite3_stmt* st = NULL; + assert(sqlite3_prepare_v2(reader, "SELECT owner_node_id,length(x25519_pubkey),length(x25519_privkey)," + "length(ed25519_pubkey),length(ed25519_privkey),length(signature) FROM channels WHERE channel_id=?", -1, &st, NULL) == SQLITE_OK); + assert(sqlite3_bind_text(st, 1, channel, -1, SQLITE_STATIC) == SQLITE_OK && sqlite3_step(st) == SQLITE_ROW); + assert((uint64_t)sqlite3_column_int64(st, 0) == inst->node_id); + for (int i = 1; i <= 5; i++) assert(sqlite3_column_int(st, i) == (i == 5 ? 64 : 32)); + assert(sqlite3_finalize(st) == SQLITE_OK); + uint8_t key[32]; assert(member_sync_author_key(inst, channel, inst->node_id, key) == MS_AUTHOR_ACTIVE); + assert(!memcmp(key, inst->my_ed25519_pubkey, 32)); channel_events++; +} + +int main(void) { + debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); size_t baseline = u_get_allocated_count(); + utun_instance_set_tun_init_enabled(0); + char directory[] = "/tmp/utun-channel-create-XXXXXX"; assert(mkdtemp(directory)); + char config[512], database[256]; + snprintf(config, sizeof(config), "[global]\ndb_path=%s\n[ntp]\nenabled=no\n" + "[chatserver]\ngroup_autoconnect=0\nstorage_autoload=0\n", directory); + struct UASYNC* ua = uasync_create(); assert(ua); + struct UTUN_INSTANCE* inst = utun_instance_create_from_str(ua, config); + assert(inst && !utun_core_start(inst) && !chat_service_start(inst)); + snprintf(database, sizeof(database), "%s/chats.db", directory); + assert(sqlite3_open_v2(database, &reader, SQLITE_OPEN_READONLY, NULL) == SQLITE_OK); + chat_event_set_handler(inst, event); assert(!channels()); + fail_sign_number = 2; chat_core_create_channel_auto(inst, "root signature failure"); + DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "channel test: after signature fault channels=%d events=%u", channels(), channel_events); + assert(!fail_sign_number && !channels() && !channel_events); + chat_core_create_channel_auto(inst, "successful retry"); assert(channels() == 1 && channel_events == 1); + utun_instance_destroy(inst); assert(channels() == 1 && sqlite3_close(reader) == SQLITE_OK); reader = NULL; + uasync_poll(ua, 0); uasync_destroy(ua, 0); assert(u_get_allocated_count() == baseline); + DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "PASS channel creation: failed root signature leaves no channel/event; retry publishes valid membership after commit"); + return 0; +}