Files
utun2/tools/chatgui/tests/test_utun_node.cpp
T
evgeny ffe563bb9f Enable VibeChat UTUN service and package the Wintun driver
Add a settings button to open the current config in an external editor. Wait for core, UTUN and chat startup before reporting readiness; verify startup failures and restarts. Include Wintun DLL and license notices in Windows builds and installers.
2026-10-19 12:33:35 +02:00

100 lines
5.3 KiB
C++

/* Desktop запускает UTUN вместе с чатом; ошибка TUN откатывает запуск до сигнала started. */
#include "../transport/utun_node.h"
#include "../transport/gui_bridge.h"
#include <QtTest>
#include <QFile>
#include <QTemporaryDir>
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<QByteArray>("settings");
QTest::addColumn<bool>("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<Probe*>(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"