From 7bf877b7d6bed96415e60c74c77836fad06d2516 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 17 Oct 2026 23:45:35 +0200 Subject: [PATCH] test(nat): exercise full retry budget with high RTT and lost reports --- tests/test_nat_detection_faults.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/tests/test_nat_detection_faults.c b/tests/test_nat_detection_faults.c index 2051f0d1..60b50911 100644 --- a/tests/test_nat_detection_faults.c +++ b/tests/test_nat_detection_faults.c @@ -7,7 +7,7 @@ enum fault_mode { FAULT_NONE, FAULT_NO_PONG, FAULT_FILTERED, FAULT_LATE_PRE, FAULT_CONTACT, FAULT_DEPENDENT, FAULT_UNSTABLE, FAULT_NO_REPORT, FAULT_INGRESS_BLOCKED, FAULT_NO_ANCHOR, FAULT_LOCAL_INGRESS, FAULT_LOCAL_OBSERVER, FAULT_LOCAL_HELPER_MAPPING, FAULT_CONTROL_STALL, FAULT_EIM_UNVERIFIED, - FAULT_KNOWN_ALIAS, FAULT_BUDGET }; + FAULT_KNOWN_ALIAS, FAULT_BUDGET, FAULT_RESUME_TIMEOUT }; static struct { struct nat_fixture *fixture; @@ -123,6 +123,10 @@ ssize_t __wrap_socket_sendto(socket_t fd, const void *packet, size_t length, con void __wrap_nat_detection_record_observation(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket, const uint8_t *key, const struct sockaddr_storage *source, const uint8_t *tag, size_t length) { + if (fault.fixture && fault.mode == FAULT_RESUME_TIMEOUT && socket->instance == fault.observer && + length == ROUTE_OBSERVE_TAG_SIZE + 9 && !memcmp(key, fault.owner->my_keys.public_key, 32)) { + fault.dropped++; return; + } if (fault.fixture && fault.mode == FAULT_EIM_UNVERIFIED && length == ROUTE_OBSERVE_TAG_SIZE + 9 && !memcmp(key, fault.owner->my_keys.public_key, 32)) { /* Два направления видят один переведённый адрес. История помощника уже загрязнена настоящим PING. */ @@ -425,14 +429,18 @@ static void run_budget_resume(void) { assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); assert(!status.phase && status.cycling && status.round == paused_round && status.helper_reselections == completed_pairs); assert(fault.socket->address_profile.inbound == ADDRESS_IN_UNKNOWN); - fault.delayed_length = 0; end = get_time_tb() + 1300000; - do { test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); } - while (get_time_tb() < end && status.round == paused_round); - assert(status.round != paused_round && status.helper == paused_helper && status.helper_reselections == completed_pairs); - uint32_t resumed_rounds = status.rounds; - /* Полный бюджет уже дан этой паре: следующий предел завершает её, а не запускает бесконечные повторы. */ - do { test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); } - while (get_time_tb() < end && status.cycling); + fault.mode = FAULT_RESUME_TIMEOUT; fault.delayed_length = 0; end = get_time_tb() + 1300000; + uint32_t resumed_rounds = 0; + /* Большой RTT увеличивает ожидание UDP-отчёта за общий предел; отчёты B теряются в сети. */ + struct ETCP_CONN *connection = instance_find_conn(owner, observer->node_id); assert(connection); + do { + for (struct ETCP_LINK *link = connection->links; link; link = link->next) link->rtt_last = 60000; + test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); + if (status.round != paused_round && !resumed_rounds) { + assert(status.helper == paused_helper && status.helper_reselections == completed_pairs); + resumed_rounds = status.rounds; + } + } while (get_time_tb() < end && status.cycling); assert(!status.phase && !status.cycling && status.round != paused_round && status.helper == paused_helper); assert(status.rounds == resumed_rounds); assert(status.helper_reselections == completed_pairs + 1 && fault.socket->address_profile.mapping == ADDRESS_MAP_UNCHANGED &&