Exercise member endpoint isolation and bootstrap over the shared ETCP transport

This commit is contained in:
evgeny committed 2026-11-04 01:00:15 +01:00
1 parent 0669cd7b06
commit 07858614c8
2 files changed
+45 -2

No files matched your search

+44 -1
View File
@@ -1086,6 +1086,49 @@ static int history_isolation(void) {
return 0;
}
static void members_done(uint64_t peer, const char* ns, int result, void* arg) {
(void)peer; (void)ns; *(int*)arg = result == MT_OK ? 1 : result;
}
/* Настоящий MEMBERS на общем ETCP: отказ выдачи в B не мешает обмену и recovery в A. */
static int members_isolation(void) {
struct UTUN_INSTANCE* server = fixture.nodes[0]; struct UTUN_INSTANCE* client = fixture.nodes[1];
struct ETCP_CONN* conn = instance_find_conn(server, client->node_id); REQUIRE(conn);
fixture.receivers[ETCP_ID_MEMBER_SYNC] = server->api_bindings.callbacks[ETCP_ID_MEMBER_SYNC];
server->api_bindings.callbacks[ETCP_ID_MEMBER_SYNC] = observe;
char sql[192]; snprintf(sql, sizeof(sql), "UPDATE peers_112 SET admitted=0 WHERE node_id=%lld", (long long)client->node_id);
REQUIRE(sqlite3_exec(server->topo_sqlite_db, sql, NULL, NULL, NULL) == SQLITE_OK);
uint8_t begin[MS_HEADER] = {ETCP_ID_MEMBER_SYNC};
ms_write64(begin + 1, 112); begin[9] = MS_BEGIN | MS_READ_ONLY; ms_write64(begin + 10, 1); begin[23] = 1;
REQUIRE(!inject(begin, sizeof(begin)));
check("MEMBERS refuses foreign-group read-only request before creating state",
!ms_find(server->msync, conn, MT_DATA_MEMBERS, 112, MS_WRITER) &&
!key_value(server, "SELECT count(*) FROM peers_112 WHERE record_state<>0"));
begin[9] = MS_BEGIN; REQUIRE(!inject(begin, sizeof(begin)));
check("MEMBERS refuses foreign-group ordinary exchange", !ms_find(server->msync, conn, MT_DATA_MEMBERS, 112, MS_EXCHANGE));
int result = 0;
REQUIRE(!member_sync_start(client, server->node_id, "111", members_done, &result));
uint64_t deadline = get_time_tb() + 50000;
while (!result && get_time_tb() < deadline) uasync_poll(fixture.ua, 1);
check("MEMBERS completes in neighbouring A through the same transport", result == 1 && fixture.transport->links_up);
member_sync_cancel(client, server->node_id, "111"); member_sync_cancel(server, client->node_id, "111");
/* Источник допускает J; J пока не получил собственную запись. Только локальный запрос. */
REQUIRE(!topo_node_sqlite_member_del(client->topo_sqlite_db, "111", client->node_id));
REQUIRE(merkle_sync_recompute_path(client, MT_DATA_MEMBERS, "111", client->node_id) >= 0);
result = 0; REQUIRE(!member_sync_start(client, server->node_id, "111", members_done, &result));
check("MEMBERS bootstrap starts an isolated reader", ms_find(client->msync, fixture.transport, MT_DATA_MEMBERS, 111, MS_READER) != NULL);
deadline = get_time_tb() + 50000;
while (!result && get_time_tb() < deadline) uasync_poll(fixture.ua, 1);
check("MEMBERS bootstrap publishes verified self membership after confirmation", result == 1 &&
topo_node_sqlite_member_allowed(client->topo_sqlite_db, "111", client->node_id) &&
!key_value(client, "SELECT count(*) FROM peers_111 WHERE record_state<>0"));
for (unsigned i = 0; i < 2; i++) member_sync_cancel(fixture.nodes[i], fixture.nodes[1-i]->node_id, "111");
REQUIRE(sqlite3_exec(server->topo_sqlite_db, "UPDATE peers_112 SET admitted=1", NULL, NULL, NULL) == SQLITE_OK);
server->api_bindings.callbacks[ETCP_ID_MEMBER_SYNC] = fixture.receivers[ETCP_ID_MEMBER_SYNC];
return 0;
}
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO);
@@ -1095,7 +1138,7 @@ int main(void) {
debug_set_category_level(DEBUG_CATEGORY_BGP, DEBUG_LEVEL_INFO);
debug_set_category_level(DEBUG_CATEGORY_MEDIA, DEBUG_LEVEL_DEBUG);
}
if (setup() || run() || invitation_isolation() || join_isolation() || nat_isolation() || multicast_isolation()) fixture.failed++;
if (setup() || members_isolation() || run() || invitation_isolation() || join_isolation() || nat_isolation() || multicast_isolation()) fixture.failed++;
else {
for (unsigned i = 0; i < 2; i++) if (member_files_init(fixture.nodes[i])) fixture.failed++;
if (!fixture.failed) {
@@ -155,10 +155,10 @@ int main() {
uint8_t signature[64] = {1};
REQUIRE(topo_node_sqlite_member_block_put(inst->topo_sqlite_db, channel.c_str(), SOURCE_A, signature, 1, signature, 2,
key, key, "{}", nullptr, 0, signature) == 0);
REQUIRE(flag(inst, channel, SOURCE_A));
/* Возвращаем placeholder: тест restart не требует поддельной криптоподписи. */
std::string sql = "UPDATE \"peers_" + channel + "\" SET source=1 WHERE node_id=42";
REQUIRE(sqlite3_exec(inst->topo_sqlite_db, sql.c_str(), nullptr, nullptr, nullptr) == SQLITE_OK);
REQUIRE(flag(inst, channel, SOURCE_A));
radio_audio_stop(); radio_audio_destroy(inst); chat_service_stop(inst);
REQUIRE(chat_service_start(inst) == 0);
REQUIRE(flag(inst, channel, SOURCE_A));