diff --git a/tests/test_etcp_packet_link.c b/tests/test_etcp_packet_link.c index 5c35413dc..a2d3bbf57 100644 --- a/tests/test_etcp_packet_link.c +++ b/tests/test_etcp_packet_link.c @@ -71,6 +71,14 @@ int main(void) { assert(first.sent == 1 && etcp_link_io_ready(a)); assert(packet_link_send(etcp_link_io_get(a), held) == PACKET_LINK_OK && first.sent == 2); + /* Счётчик ETCP измеряет принятие драйвером, включая временную очередь UDP; отказ не считается. */ + uint64_t sent_before = conn->diagnostic_wire_tx_bytes; + const uint8_t value = 42; first.blocked = 1; + assert(etcp_link_io_send(a, &value, 1) == 1 && conn->diagnostic_wire_tx_bytes == sent_before + 1); + assert(etcp_link_io_send(a, &value, 1) == -2 && conn->diagnostic_wire_tx_bytes == sent_before + 1); + first.blocked = 0; etcp_link_io_socket_writable(sock.fd, &sock); + assert(conn->diagnostic_wire_tx_bytes == sent_before + 1 && etcp_link_io_ready(a)); + /* Подготовка не снимает ACK; отказ не меняет очередь/служебные признаки. */ b->initialized = b->link_status = 0; struct ACK_PACKET* ack = (struct ACK_PACKET*)queue_entry_new_from_pool(inst.ack_pool); assert(ack); diff --git a/tools/chatgui/tests/test_call_commands.cpp b/tools/chatgui/tests/test_call_commands.cpp index babd0976a..303ce238f 100644 --- a/tools/chatgui/tests/test_call_commands.cpp +++ b/tools/chatgui/tests/test_call_commands.cpp @@ -1,6 +1,8 @@ /* Настоящие CallWindow/bridge/uasync: владение call-командами при отказе, отмене и исполнении. * Linux hooks наблюдают границу native trampoline и затем вызывают его без подмены освобождения payload. */ #include "../src/callwindow.h" +#include "../src/call_audio_graphs.h" +#include "call/call_history_store.h" #include "../src/call_camera_capture.h" #include "../src/call_video_engine.h" #include "../transport/gui_bridge.h" @@ -161,6 +163,28 @@ private slots: observed.clear(); bindingValid = true; QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); } + void audioHistoryGraphs() { + CallWindow window; window.setCallId(77); window.setState(CallWindow::Active); window.show(); + auto* button = window.findChild("callAudioGraphsButton"); QVERIFY(button); QVERIFY(button->isVisible()); + button->click(); + auto* child = window.findChild("callAudioGraphs"); QVERIFY(child); QVERIFY(child->isVisible()); + auto* graphs = static_cast(child); + CallHistoryStore history; uint64_t sent = 0; + for (int i = 0; i < 600; ++i) { + int depth = 500 + (int)(250 * std::sin(i / 25.0)); + bool missing = i >= 230 && i < 245; + history.receive(i * 50, missing ? 0 : depth, 200, 100, 2400, missing ? 2400 : 0); + sent += i % 4 == 0 ? 500 : 0; + history.transmit({(uint64_t)i * 50, (uint64_t)(i % 100) * 20, 800, 1200, 42, 9, sent}); + } + call_audio_history snapshot; history.snapshot(29950, snapshot); graphs->setSnapshot(snapshot); + QCoreApplication::processEvents(); QVERIFY(!graphs->grab().isNull()); + const QString screenshot = qEnvironmentVariable("UTUN_TEST_AUDIO_GRAPHS_SCREENSHOT"); + if (!screenshot.isEmpty()) QVERIFY(graphs->grab().save(screenshot)); + graphs->close(); QVERIFY(!graphs->isVisible()); QCOMPARE(window.state(), CallWindow::Active); + button->click(); QVERIFY(graphs->isVisible()); + window.setState(CallWindow::Ended); + } void videoSettingsMenus() { CallWindow window; window.setCallId(77); window.setPeerName(QStringLiteral("Video call")); window.setState(CallWindow::Active); auto* engine = window.findChild(); QVERIFY(engine); diff --git a/tools/chatgui/tests/test_call_jitter.cpp b/tools/chatgui/tests/test_call_jitter.cpp index 27af4acad..abfb12e79 100644 --- a/tools/chatgui/tests/test_call_jitter.cpp +++ b/tools/chatgui/tests/test_call_jitter.cpp @@ -218,6 +218,17 @@ static void test_audio_history() { history.snapshot(89950, snapshot); CHECK(snapshot.rx_count == 600 && snapshot.rx[0].at_ms == 60000); CHECK(std::abs(snapshot.histogram[60] - 1) < .001); + CallHistoryStore traffic; + for (unsigned i = 0; i <= 20; ++i) traffic.transmit({1000 + i * 50, 0, 0, 0, 42, 7, i * 100}); + traffic.snapshot(2000, snapshot); + CHECK(snapshot.tx[0].wire_bytes_per_sec == -1); + CHECK(snapshot.tx[20].wire_bytes_per_sec == 2000); + traffic.transmit({2050, 0, 0, 0, 43, 8, 900000}); traffic.snapshot(2050, snapshot); + CHECK(snapshot.tx[21].wire_bytes_per_sec == -1); // Смена пути не выглядит скачком трафика. + traffic.transmit({2100, 0, 0, 0, 43, 8, 900100}); traffic.snapshot(2100, snapshot); + CHECK(snapshot.tx[22].wire_bytes_per_sec == 2000); + traffic.transmit({2400, 0, 0, 0, 43, 8, 900200}); traffic.snapshot(2400, snapshot); + CHECK(snapshot.tx[23].wire_bytes_per_sec == -1); // Пропущенные измерения не интерполируются. puts("audio history: time weights, startup exclusion, gaps, overflow bin and ring expiry PASS"); }