Files
utun2/tools/chatgui/tests/test_desktop_ble.cpp
T
evgeny f84622966e Add BLE ETCP links and GATT invitations for desktop and Android
Attach packet drivers to initially empty ETCP connections. Share BLE neighbor
tracking and group fallback between desktop and Android in cgathui_common.

Deliver join links through a dedicated Write/Indicate characteristic with
independent fragmentation queues, application acknowledgements, deduplication
and bounded retries. Merge LAN/BLE discovery and add a separate Bluetooth
invitation reception setting to both clients.

Validation: 230 core tests, BLE transport/BlueZ/UI tests, ASAN/UBSAN,
Linux GUI and Android builds, and Windows backend cross-compilation.
Physical Android/Linux invitation exchange passed with either GATT initiator.
The Android-initiated run also verified all 32 ETCP packets of 1500 bytes;
the desktop-initiated load run reached 7/32 within its 45-second time limit.
2026-10-29 16:41:04 +01:00

63 lines
3.6 KiB
C++

/* Настоящий frontend и C-транспорт, управляемый backend без радио/системной шины. */
#include "../transport/desktop_ble.h"
#include "../../../lib/ble/ble_backend.h"
#include "../../../lib/ble/ble_identity.h"
#include "../../../lib/u_async.h"
#include "../../../lib/debug_config.h"
#include <QtTest>
#include <memory>
struct ble_backend { ble_transport* owner = nullptr; };
static ble_backend backend;
static int creations, destructions, advertisements;
static QByteArray advertised;
extern "C" ble_backend* ble_backend_create(ble_transport* owner, UASYNC*, const ble_config*) {
backend.owner = owner; ++creations; return &backend;
}
extern "C" void ble_backend_destroy(ble_backend*) { backend.owner = nullptr; ++destructions; }
extern "C" int ble_backend_advertise(ble_backend*, const uint8_t* data, size_t len) {
advertised = QByteArray(reinterpret_cast<const char*>(data), int(len)); ++advertisements; return 0;
}
extern "C" int ble_backend_connect(ble_backend*, ble_link_id, const ble_endpoint*) { return BLE_ERROR; }
extern "C" void ble_backend_close(ble_backend*, ble_link_id) {}
extern "C" int ble_backend_send(ble_backend*, ble_link_id, enum ble_channel, const uint8_t*, size_t) { return BLE_ERROR; }
class DesktopBleTest : public QObject {
Q_OBJECT
private slots:
void policyAndDiscovery() {
debug_config_init();
auto destroy = [](UASYNC* ua) { uasync_destroy(ua, 0); };
std::unique_ptr<UASYNC, decltype(destroy)> ua(uasync_create(), destroy); QVERIFY(ua);
DesktopBle radio(ua.get(), 1);
radio.apply(0, "Desktop"); QVERIFY(!radio.transport()); QCOMPARE(creations, 0);
radio.apply(3, "Desktop"); QVERIFY(radio.transport()); QCOMPARE(creations, 1);
QCOMPARE(radio.snapshot().state, BLE_STARTING); QCOMPARE(advertisements, 0);
ble_endpoint endpoint{}; strcpy(endpoint.id, "peer");
QCOMPARE(ble_backend_incoming(backend.owner, &endpoint), ble_link_id(0));
ble_backend_status(backend.owner, 1, "ready"); QCOMPARE(advertisements, 1);
ble_identity identity{};
QCOMPARE(ble_identity_decode(&identity, reinterpret_cast<const uint8_t*>(advertised.constData()), advertised.size()), 0);
QCOMPARE(identity.node_id, uint64_t(1)); QCOMPARE(QByteArray(identity.name), QByteArray("Desktop"));
radio.apply(3, "Desktop"); QCOMPARE(advertisements, 1);
radio.apply(7, "Renamed"); QCOMPARE(advertisements, 2);
QVERIFY(ble_backend_incoming(backend.owner, &endpoint) != 0);
uint8_t bytes[24]; int length = ble_identity_encode(bytes, 2, "Android");
ble_backend_broadcast(backend.owner, &endpoint, bytes, length, -42);
const auto peers = radio.snapshot().peers;
QCOMPARE(peers.size(), 1); QVERIFY(peers.first().contains("Android")); QVERIFY(peers.first().contains("-42"));
ble_backend_broadcast(backend.owner, &endpoint, bytes, length, -40);
QCOMPARE(radio.snapshot().peers.size(), 1);
radio.apply(1, "Renamed"); QVERIFY(advertised.isEmpty());
QCOMPARE(ble_backend_incoming(backend.owner, &endpoint), ble_link_id(0));
radio.apply(0, "Renamed"); QVERIFY(!radio.transport()); QCOMPARE(destructions, 1);
QVERIFY(radio.snapshot().peers.isEmpty()); QCOMPARE(radio.snapshot().state, BLE_CLOSED);
radio.apply(1, "Renamed"); QCOMPARE(creations, 2);
ble_backend_status(backend.owner, 0, "adapter is off");
QCOMPARE(radio.snapshot().reason, QString("adapter is off"));
radio.apply(0, "Renamed"); QCOMPARE(destructions, 2);
}
};
QTEST_GUILESS_MAIN(DesktopBleTest)
#include "test_desktop_ble.moc"