/* Desktop запускает UTUN вместе с чатом; ошибка TUN откатывает запуск до сигнала started. */ #include "../transport/utun_node.h" #include "../transport/gui_bridge.h" #include #include #include extern "C" { #include "utun_instance.h" #include "tun_if.h" #include "routing_layer/topo_group.h" #include "u_async.h" #include "debug_config.h" } static const QByteArray identity = "my_private_key=704f2e012c8fa8768130cb0f988a997dccb628372bc5ceccacc78dcbfec5916f\n" "my_public_key=b3193173def895bd0fcea6f86af077c7d77216f10395275f627ac18242ec0f01\n"; class UtunNodeTest : public QObject { Q_OBJECT private slots: void initTestCase() { gui_bridge_init(); } void cleanup() { debug_disable_file_output(); } void services_data() { QTest::addColumn("settings"); QTest::addColumn("withTun"); QTest::newRow("chat-default") << QByteArray() << false; QTest::newRow("tun-disabled") << QByteArray("tun_enabled=no\ntun_ifname=unused\ntun_ip=198.18.0.1\n") << false; #ifndef Q_OS_WIN QTest::newRow("tun-queues") << QByteArray("tun_enabled=yes\ntun_test_mode=1\ntun_ifname=vibetest\ntun_ip=198.18.0.1\n") << true; #endif if (qEnvironmentVariableIsSet("UTUN_TEST_REAL_TUN")) QTest::newRow("tun-real") << QByteArray("tun_enabled=yes\ntun_ifname=vibetest\ntun_ip=198.18.0.1\n") << true; } void services() { QFETCH(QByteArray, settings); QFETCH(bool, withTun); QTemporaryDir directory; QVERIFY(directory.isValid()); const QString path = directory.filePath("node.cfg"); QFile config(path); QVERIFY(config.open(QIODevice::WriteOnly)); const QByteArray text = "[global]\n" + identity + settings + "[server:local]\naddr=127.0.0.1:0\ntype=private\n" "[chatserver]\ngroup_autoconnect=0\nstorage_autoload=0\n[ntp]\nenabled=no\n"; QCOMPARE(config.write(text), text.size()); config.close(); UtunNode node; node.setDbPath(directory.filePath("db")); node.setDebugFile(directory.filePath("node.log")); node.setDebugCategories("sys=info,tun=debug,general=info"); QSignalSpy started(&node, &UtunNode::started); for (int attempt = 0; attempt < 2; ++attempt) { const bool running = node.start(path); if (!running) { directory.setAutoRemove(false); qWarning() << "Startup diagnostics:" << directory.filePath("node.log"); } QVERIFY(running); QCOMPARE(started.count(), attempt + 1); QVERIFY(node.isRunning() && gui_bridge_is_uasync_ready()); bool ready = false, valid = false; struct Probe { QObject* receiver; bool* ready; bool* valid; bool tun; } probe{this, &ready, &valid, withTun}; gui_bridge_post_uasync_fn([](void* arg) { auto* p = static_cast(arg); auto* inst = gui_bridge_get_inst(); const bool ok = inst && inst->core_started && inst->utun_started && inst->chat_started && uasync_is_running(inst->ua) && topo_groups_get_default(inst->topo_groups) && (inst->tun != nullptr) == p->tun; DEBUG_INFO(DEBUG_CATEGORY_TUN, "desktop startup test: services=%d expected_tun=%d", ok, p->tun); QMetaObject::invokeMethod(p->receiver, [p, ok] { *p->valid = ok; *p->ready = true; }, Qt::QueuedConnection); }, &probe); QTRY_VERIFY_WITH_TIMEOUT(ready, 3000); QVERIFY(valid); node.stop(); QVERIFY(!node.isRunning() && !node.instance() && !gui_bridge_get_inst() && !gui_bridge_is_uasync_ready()); } } void tunFailureRejectsStartup() { QTemporaryDir directory; QVERIFY(directory.isValid()); const QString path = directory.filePath("node.cfg"); QFile config(path); QVERIFY(config.open(QIODevice::WriteOnly)); // Нет tun_ip: отказ до обращения к ОС воспроизводится и на Windows без установленного драйвера. const QByteArray text = "[global]\n" + identity + "tun_enabled=yes\n[server:local]\naddr=127.0.0.1:0\ntype=private\n[ntp]\nenabled=no\n"; QCOMPARE(config.write(text), text.size()); config.close(); UtunNode node; node.setDbPath(directory.filePath("db")); node.setDebugFile(directory.filePath("node.log")); QSignalSpy started(&node, &UtunNode::started), errors(&node, &UtunNode::error); QVERIFY(!node.start(path)); QCOMPARE(started.count(), 0); QVERIFY(!node.isRunning() && !node.instance() && !gui_bridge_get_inst() && !gui_bridge_is_uasync_ready()); QTRY_COMPARE(errors.count(), 1); const QString error = errors.first().first().toString(); QVERIFY2(error.contains("utun_service_start"), qPrintable(error)); QVERIFY(config.open(QIODevice::WriteOnly | QIODevice::Truncate)); QByteArray disabled = text; disabled.replace("tun_enabled=yes", "tun_enabled=no"); QCOMPARE(config.write(disabled), disabled.size()); config.close(); QVERIFY(node.start(path)); QCOMPARE(started.count(), 1); node.stop(); QVERIFY(!node.isRunning() && !gui_bridge_is_uasync_ready()); } }; QTEST_MAIN(UtunNodeTest) #include "test_utun_node.moc"