diff --git a/tests/test_chat_group_isolation.c b/tests/test_chat_group_isolation.c index b1f15fcb9..b1ad2540e 100644 --- a/tests/test_chat_group_isolation.c +++ b/tests/test_chat_group_isolation.c @@ -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) { diff --git a/tools/chatgui/tests/test_radio_member_mute.cpp b/tools/chatgui/tests/test_radio_member_mute.cpp index ac005dd4f..9ec9ccf14 100644 --- a/tools/chatgui/tests/test_radio_member_mute.cpp +++ b/tools/chatgui/tests/test_radio_member_mute.cpp @@ -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));