Model admitted CHAT members in media test fixtures

This commit is contained in:
evgeny committed 2026-11-03 18:56:36 +01:00
1 parent 7255e76ef7
commit 2b37d071b5
3 files changed
+54 -15

No files matched your search

+7 -2
View File
@@ -10,6 +10,7 @@
* Стенд сохраняет владение router: пакет потребляется даже при ошибке. Ответы доставляются отдельно,
* поэтому можно проверить задержки, дубликаты, чужие ответы и состояние между пачками. */
#include "test_utils.h"
#include "media_members_fixture.h"
#include "../src/utun_instance.h"
#include "../src/chat/chat_core_priv.h"
#include "../src/media_delivery/media_index.h"
@@ -59,7 +60,8 @@ int __wrap_RAND_bytes(unsigned char* out, int count) {
* В обоих исходах потребляет entry/dgram, как настоящий router; sent_hook вызывается только при успехе. */
int __wrap_etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t dst,
struct ll_entry* entry, int force, int mode) {
(void)force; (void)mode;
(void)force;
REQUIRE(mode == (ROUTER_FLAG_SIGNED | ROUTER_FLAG_ENCRYPTED));
int cmd = entry->dgram[1], rc = cmd == fail_send ? -1 : 0;
if (cmd == MEDIA_SUBCMD_SYNC_REQ || cmd == MEDIA_SUBCMD_SYNC_RESP || cmd == MEDIA_SUBCMD_CHANGED) REQUIRE(!force);
if (cmd == MEDIA_SUBCMD_BLOCK_REQ) request_count++;
@@ -117,6 +119,9 @@ static struct UTUN_INSTANCE* instance(uint64_t node) {
inst->ua = ua; inst->node_id = node;
inst->chat_core = u_calloc(1, sizeof(struct chat_core_ctx)); REQUIRE(inst->chat_core);
REQUIRE(sqlite3_open(":memory:", &inst->topo_sqlite_db) == SQLITE_OK);
const uint64_t peers[] = {SERVER, SERVER + 1, SERVER + 2, CLIENT, 0x300, 0x301, 0x302, 0x303, 0x304, 0x400, 0x900,
1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012};
media_test_group(inst, GROUP, peers, sizeof(peers) / sizeof(*peers));
REQUIRE(!etcp_router_init(inst) && !media_index_init(inst->topo_sqlite_db) && !media_delivery_init(inst));
uint8_t pubkey[32]; size_t length = sizeof(pubkey);
EVP_PKEY* key = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, author_key, 32); REQUIRE(key);
@@ -133,7 +138,7 @@ static struct UTUN_INSTANCE* instance(uint64_t node) {
/* Уничтожить media/router/SQLite/chat_core этого стенда и выполнить poll(0); inst обязателен, повтор не допускается.
* Дополнительными ресурсами, которые тест сам добавил в inst (например topo_groups), владеет caller. */
static void destroy(struct UTUN_INSTANCE* inst) {
media_delivery_destroy(inst); etcp_router_destroy(inst); sqlite3_close(inst->topo_sqlite_db);
media_delivery_destroy(inst); etcp_router_destroy(inst); media_test_groups_free(inst); sqlite3_close(inst->topo_sqlite_db);
u_free(inst->chat_core); u_free(inst); uasync_poll(ua, 0);
}
+45
View File
@@ -0,0 +1,45 @@
/* Минимальная CHAT-топология и результат проверки member_sync для unit-тестов медиа.
* Не моделирует подписи участников: сетевые тесты используют test_membership.h. */
#ifndef MEDIA_MEMBERS_FIXTURE_H
#define MEDIA_MEMBERS_FIXTURE_H
#include "../src/utun_instance.h"
#include "../src/routing_layer/topo_group.h"
#include "../lib/mem.h"
#include "../lib/debug_config.h"
#include <stdlib.h>
#include <stdio.h>
static void media_test_group(struct UTUN_INSTANCE* inst, uint64_t id, const uint64_t* peers, size_t count) {
if (!inst->topo_groups) {
inst->topo_groups = u_calloc(1, sizeof(*inst->topo_groups));
if (!inst->topo_groups) abort();
inst->topo_groups->instance = inst;
inst->topo_groups->group_list = queue_new(inst->ua, 16, 0, 8, "media_test_groups");
if (!inst->topo_groups->group_list) abort();
}
if (!topo_groups_find(inst->topo_groups, id)) {
struct TOPO_GROUP* g = (void*)queue_entry_new(sizeof(*g) - sizeof(struct ll_entry));
if (!g) abort();
g->instance = inst; g->group_id = id; g->group_type = TOPO_GROUP_TYPE_CHAT;
snprintf(g->channel_id, sizeof(g->channel_id), "%llu", (unsigned long long)id);
if (queue_data_put_with_index(inst->topo_groups->group_list, &g->ll)) abort();
}
char sql[512];
snprintf(sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS peers_%llu(node_id INTEGER PRIMARY KEY,source INTEGER DEFAULT 0,"
"deleted INTEGER DEFAULT 0,admitted INTEGER DEFAULT 1,node_type INTEGER DEFAULT 0,adm_tags TEXT DEFAULT '{}')",
(unsigned long long)id);
if (sqlite3_exec(inst->topo_sqlite_db, sql, NULL, NULL, NULL) != SQLITE_OK) abort();
for (size_t i = 0; i <= count; i++) {
snprintf(sql, sizeof(sql), "INSERT OR IGNORE INTO peers_%llu(node_id) VALUES(%lld)",
(unsigned long long)id, (long long)(i == count ? inst->node_id : peers[i]));
if (sqlite3_exec(inst->topo_sqlite_db, sql, NULL, NULL, NULL) != SQLITE_OK) abort();
}
}
/* Только для минимальных групп этого стенда, после остановки media/router. */
static void media_test_groups_free(struct UTUN_INSTANCE* inst) {
if (!inst->topo_groups) return;
queue_clear(inst->topo_groups->group_list); queue_free(inst->topo_groups->group_list);
u_free(inst->topo_groups); inst->topo_groups = NULL;
}
#endif
+2 -13
View File
@@ -58,18 +58,9 @@ static void write_le(void* ptr, uint64_t v, unsigned n) {
/* Только транспорт управляемый: каталог, роли, router-очереди и обработчики — настоящие.
* Таблица peers отражает результат уже проверенного member_sync; криптография членства проверяется его тестами. */
static void add_group(struct UTUN_INSTANCE* inst, uint64_t group) {
if (!inst->topo_groups) {
inst->topo_groups = u_calloc(1, sizeof(*inst->topo_groups)); REQUIRE(inst->topo_groups);
inst->topo_groups->instance = inst;
inst->topo_groups->group_list = queue_new(ua, 16, 0, 8, "test_groups"); REQUIRE(inst->topo_groups->group_list);
}
struct ll_entry* e = queue_entry_new(sizeof(struct TOPO_GROUP) - sizeof(struct ll_entry)); REQUIRE(e);
struct TOPO_GROUP* g = (struct TOPO_GROUP*)e;
g->instance = inst; g->group_id = group; g->group_type = TOPO_GROUP_TYPE_CHAT;
snprintf(g->channel_id, sizeof(g->channel_id), "%llu", (unsigned long long)group);
queue_data_put_with_index(inst->topo_groups->group_list, e);
media_test_group(inst, group, NULL, 0);
char command[512];
snprintf(command, sizeof(command), "CREATE TABLE peers_%llu(node_id INTEGER PRIMARY KEY,adm_tags TEXT,admitted INTEGER DEFAULT 1);"
snprintf(command, sizeof(command), "DELETE FROM peers_%llu;"
"INSERT INTO peers_%llu(node_id,adm_tags) VALUES(256,'{\"supernode\":\"yes\"}'),(512,'{\"supernode\":\"yes\"}'),(768,'{\"supernode\":\"yes\"}')",
(unsigned long long)group, (unsigned long long)group);
sql(inst->md.db, command);
@@ -81,9 +72,7 @@ static struct UTUN_INSTANCE* node(uint64_t id) {
}
static void free_node(struct UTUN_INSTANCE* inst) {
struct TOPO_GROUPS* groups = inst->topo_groups;
destroy(inst);
if (groups) { queue_free(groups->group_list); u_free(groups); }
}
static struct media_super_peer* peer(struct UTUN_INSTANCE* inst, uint64_t remote, uint64_t group) {