Test automatic socket protocol configuration and Android port reuse

This commit is contained in:
evgeny committed 2026-10-25 16:35:54 +01:00
1 parent b1a07df606
commit fc8a06547d
3 files changed
+101

No files matched your search

+22
View File
@@ -210,6 +210,27 @@ static void test_debug_log_reopen(void) {
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Log reopen success/failure and append preservation: PASS");
}
/* Значение по умолчанию, все режимы и строгая проверка протоколов автосокетов. */
static void test_auto_socket_protocols(void) {
static const struct { const char* value; int mask; } cases[] = {
{"", CFG_AUTO_SOCKET_BOTH}, {"tcp", CFG_AUTO_SOCKET_TCP}, {"udp", CFG_AUTO_SOCKET_UDP},
{"tcp+udp", CFG_AUTO_SOCKET_BOTH}, {"TCP+UDP", CFG_AUTO_SOCKET_BOTH}, {"TCP", CFG_AUTO_SOCKET_TCP},
{"udp+tcp", 0}, {"none", 0}, {"invalid", 0}
};
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
char text[128];
int length = snprintf(text, sizeof(text), "[global]\nauto_sockets=yes\n%s%s\n",
cases[i].value[0] ? "auto_socket_protocols=" : "", cases[i].value);
struct utun_config* config = parse_config_from_buf(text, length, "auto-socket-protocols");
if (!cases[i].mask) { assert(!config); continue; }
assert(config && config->global.auto_socket_protocols == cases[i].mask);
free_config(config);
}
const char* empty = "[global]\nauto_socket_protocols=\n";
assert(!parse_config_from_buf(empty, strlen(empty), "empty-auto-socket-protocols"));
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Auto socket protocols: defaults, valid values and rejection verified");
}
int main() {
// Initialize socket platform (required for getaddrinfo on Windows)
if (socket_platform_init() != 0) {
@@ -270,6 +291,7 @@ int main() {
test_all_debug_categories();
test_debug_output_contract();
test_debug_log_reopen();
test_auto_socket_protocols();
// Cleanup temp config file
cleanup_temp_config();
@@ -0,0 +1,45 @@
package com.utun.chat.data
import org.junit.Assert.*
import org.junit.Test
class AutoSocketProtocolsTest {
@Test fun createsOnlySelectedProtocolsForBothFamilies() {
for (mode in AutoSocketProtocols.values()) {
for (ip in listOf("192.168.1.2", "fd42::2")) {
val entries = mode.createServers("wlan_0", ip, emptyList())
assertEquals(mode.protocols, entries.map { it.protocol })
assertTrue(entries.all { it.ifName == "wlan_0" && it.bindIp == ip && it.port in 2000..9999 })
}
}
}
@Test fun keepsPortsSeparateByInterfaceFamilyAndProtocol() {
val saved = listOf(
ServerEntry("1", "wlan0", "192.168.1.2", "tcp", 2001),
ServerEntry("2", "wlan0", "192.168.1.2", "udp", 2002),
ServerEntry("3", "wlan0", "fd42::2", "tcp", 2003),
ServerEntry("4", "wlan0", "fd42::2", "udp", 2004),
ServerEntry("5", "rmnet0", "192.168.1.2", "tcp", 2005)
)
val v4 = AutoSocketProtocols.BOTH.createServers("wlan0", "192.168.2.3", saved)
val v6 = AutoSocketProtocols.BOTH.createServers("wlan0", "fd42::3", saved)
assertEquals(listOf(2001, 2002), v4.map { it.port })
assertEquals(listOf(2003, 2004), v6.map { it.port })
assertEquals(2005, AutoSocketProtocols.TCP.createServers("rmnet0", "10.0.0.2", saved).single().port)
assertEquals(4, (v4 + v6).map { it.sectionName }.toSet().size)
assertEquals(4, (v4 + v6).map { it.socketKey }.toSet().size)
}
@Test fun restoresDisabledProtocolsAndMissingInterfaces() {
val saved = AutoSocketProtocols.BOTH.createServers("wlan0", "192.168.1.2", emptyList()) +
AutoSocketProtocols.BOTH.createServers("rmnet0", "10.0.0.2", emptyList())
val active = AutoSocketProtocols.TCP.createServers("wlan0", "192.168.2.3", saved)
val activeKeys = active.map { it.socketKey }.toSet()
val inactive = saved.filter { it.socketKey !in activeKeys }
assertEquals(3, inactive.size)
val restored = AutoSocketProtocols.BOTH.createServers("wlan0", "192.168.3.4", active + inactive) +
AutoSocketProtocols.BOTH.createServers("rmnet0", "10.0.1.2", active + inactive)
assertEquals(saved.associate { it.socketKey to it.port }, restored.associate { it.socketKey to it.port })
}
}
+34
View File
@@ -52,6 +52,40 @@ private slots:
QCOMPARE(resolveGuiLanguage("en", {"ru-RU"}), QString("en"));
}
void autoSocketProtocols() {
QTemporaryDir directory;
QVERIFY(directory.isValid());
const QString path = directory.filePath("protocols.cfg");
NodeConfig config(path);
QVERIFY(config.create("Protocol test", 1333));
NetworkSettingsPage page; page.loadFromConfig(path);
auto* protocols = page.findChild<QComboBox*>("autoSocketProtocols");
QVERIFY(protocols && protocols->isEnabled());
QCOMPARE(protocols->currentData().toString(), QString("tcp+udp"));
for (const QString& value : {QString("tcp"), QString("udp"), QString("tcp+udp")}) {
protocols->setCurrentIndex(protocols->findData(value));
QVERIFY(page.saveToConfig(path));
QVERIFY(config.load());
QVERIFY2(!config.hasErrors(), qPrintable(config.errors().join('\n')));
QCOMPARE(config.autoSocketProtocols(), value);
QVERIFY(config.save());
QVERIFY(config.load()); QCOMPARE(config.autoSocketProtocols(), value);
QVERIFY(config.saveFull());
QVERIFY(config.load()); QCOMPARE(config.autoSocketProtocols(), value);
page.loadFromConfig(path);
QCOMPARE(protocols->currentData().toString(), value);
}
QVERIFY(config_update_option(path, "global", "auto_sockets", "no"));
page.loadFromConfig(path); QVERIFY(!protocols->isEnabled());
QVERIFY(config_update_option(path, "global", "auto_socket_protocols", "invalid"));
QVERIFY(config.load()); QVERIFY(config.hasErrors());
QFile file(path); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Truncate));
const QByteArray minimal("[global]\nauto_sockets=yes\n");
QCOMPARE(file.write(minimal), qint64(minimal.size())); file.close();
QVERIFY(config.load()); QCOMPARE(config.autoSocketProtocols(), QString("tcp+udp"));
page.loadFromConfig(path); QCOMPARE(protocols->currentData().toString(), QString("tcp+udp"));
}
void preferencePersistence() {
QTemporaryDir directory;
QVERIFY(directory.isValid());