diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index be0b52be8b50ecf45f11e2f9fbe5939e5084771c..e8f3512a41e9e21c428443ad8534278347e8d282 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -188,7 +188,8 @@ DebugBuild { src/qgcunittest/MockQGCUASParamManager.h \ src/qgcunittest/MultiSignalSpy.h \ src/qgcunittest/FlightModeConfigTest.h \ - src/qgcunittest/TCPLinkTest.h + src/qgcunittest/TCPLinkTest.h \ + src/qgcunittest/TCPLoopBackServer.h SOURCES += \ src/qgcunittest/UASUnitTest.cc \ @@ -197,7 +198,8 @@ DebugBuild { src/qgcunittest/MockQGCUASParamManager.cc \ src/qgcunittest/MultiSignalSpy.cc \ src/qgcunittest/FlightModeConfigTest.cc \ - src/qgcunittest/TCPLinkTest.cc + src/qgcunittest/TCPLinkTest.cc \ + src/qgcunittest/TCPLoopBackServer.cc } # diff --git a/src/comm/TCPLink.cc b/src/comm/TCPLink.cc index 146e7a39306b03d4a67b4b370894f6f563a19f19..7eee21cf5b6356b3c53da479754cfe4c3068fcba 100644 --- a/src/comm/TCPLink.cc +++ b/src/comm/TCPLink.cc @@ -306,3 +306,15 @@ void TCPLink::_resetName(void) _name = QString("TCP Link (host:%1 port:%2)").arg(_hostAddress.toString()).arg(_port); emit nameChanged(_name); } + +void TCPLink::waitForBytesWritten(int msecs) +{ + Q_ASSERT(_socket); + _socket->waitForBytesWritten(msecs); +} + +void TCPLink::waitForReadyRead(int msecs) +{ + Q_ASSERT(_socket); + _socket->waitForReadyRead(msecs); +} diff --git a/src/comm/TCPLink.h b/src/comm/TCPLink.h index b7e7fe72e7796e698acbb4c9e2f94dfbb5d9ed2a..38da51e6838bad08de4ea1cb9253310b3fead769 100644 --- a/src/comm/TCPLink.h +++ b/src/comm/TCPLink.h @@ -60,6 +60,8 @@ public: quint16 getPort(void) const { return _port; } QTcpSocket* getSocket(void) { return _socket; } + void signalBytesWritten(void); + // LinkInterface methods virtual int getId(void) const; virtual QString getName(void) const; @@ -80,6 +82,9 @@ public slots: // From LinkInterface virtual void writeBytes(const char* data, qint64 length); + + void waitForBytesWritten(int msecs); + void waitForReadyRead(int msecs); protected slots: void _socketError(QAbstractSocket::SocketError socketError); @@ -90,7 +95,7 @@ protected slots: protected: // From LinkInterface->QThread virtual void run(void); - + private: void _resetName(void); bool _hardwareConnect(void); diff --git a/src/qgcunittest/MultiSignalSpy.cc b/src/qgcunittest/MultiSignalSpy.cc index 4cebd834785cd2f20b527f8318b37a7d46f2fbd6..5d8d87c015c5c64eb9d1cab6deab2287b259eae7 100644 --- a/src/qgcunittest/MultiSignalSpy.cc +++ b/src/qgcunittest/MultiSignalSpy.cc @@ -25,6 +25,7 @@ #include #include #include +#include /// @file /// @brief This class allows you to keep track of signal counts on a set of signals associated with an object. @@ -218,7 +219,10 @@ bool MultiSignalSpy::waitForSignalByIndex( Q_ASSERT(spy); while (spy->count() == 0 && !_timeout) { - QCoreApplication::processEvents(QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents, 500); + QCoreApplication::sendPostedEvents(); + QCoreApplication::processEvents(); + QCoreApplication::flush(); + QTest::qSleep(100); } // Clean up and return status diff --git a/src/qgcunittest/TCPLinkTest.cc b/src/qgcunittest/TCPLinkTest.cc index 045c4e51f527f593187c671d991ee77695c1cd0a..50471251e7f5f9b5128669109893e8bb52d90ece 100644 --- a/src/qgcunittest/TCPLinkTest.cc +++ b/src/qgcunittest/TCPLinkTest.cc @@ -22,7 +22,7 @@ ======================================================================*/ #include "TCPLinkTest.h" -#include +#include "TCPLoopBackServer.h" /// @file /// @brief TCPLink class unit test @@ -143,51 +143,46 @@ void TCPLinkUnitTest::_connectSucceed_test(void) Q_ASSERT(_multiSpy->checkNoSignals() == true); // Start the server side - QTcpServer* server = new QTcpServer(this); - QCOMPARE(server->listen(_hostAddress, _port), true); + TCPLoopBackServer* server = new TCPLoopBackServer(_hostAddress, _port); + Q_CHECK_PTR(server); // Connect to the server QCOMPARE(_link->connect(), true); - // Wait for the connection to come through on server side - QCOMPARE(server->waitForNewConnection(1000), true); - QTcpSocket* serverSocket = server->nextPendingConnection(); - Q_ASSERT(serverSocket); - // Make sure we get the two different connected signals QCOMPARE(_multiSpy->waitForSignalByIndex(connectedSignalIndex, 1000), true); QCOMPARE(_multiSpy->checkOnlySignalByMask(connectedSignalMask | connected2SignalMask), true); QList arguments = _multiSpy->getSpyByIndex(connected2SignalIndex)->takeFirst(); QCOMPARE(arguments.at(0).toBool(), true); - _multiSpy->clearSignalsByMask(connectedSignalMask); - - // Test server->link data path - - QByteArray bytesOut("test"); - - // Write data from server to link - serverSocket->write(bytesOut); - - // Make sure we get the bytesReceived signal, with the correct data - QCOMPARE(_multiSpy->waitForSignalByIndex(bytesReceivedSignalIndex, 1000), true); - QCOMPARE(_multiSpy->checkOnlySignalByMask(bytesReceivedSignalMask), true); - arguments = _multiSpy->getSpyByIndex(bytesReceivedSignalIndex)->takeFirst(); - QCOMPARE(arguments.at(1), QVariant(bytesOut)); - _multiSpy->clearSignalByIndex(bytesReceivedSignalIndex); + _multiSpy->clearAllSignals(); // Test link->server data path + QByteArray bytesOut("test"); + // Write data from link to server + const char* bytesWrittenSignal = SIGNAL(bytesWritten(qint64)); + MultiSignalSpy bytesWrittenSpy; + QCOMPARE(bytesWrittenSpy.init(_link->getSocket(), &bytesWrittenSignal, 1), true); _link->writeBytes(bytesOut.data(), bytesOut.size()); - QCOMPARE(_link->getSocket()->waitForBytesWritten(1000), true); + _multiSpy->clearAllSignals(); + + // We emit this signal such that it will be queued and run on the TCPLink thread. This in turn + // allows the TCPLink object to pump the bytes through. + connect(this, SIGNAL(waitForBytesWritten(int)), _link, SLOT(waitForBytesWritten(int))); + emit waitForBytesWritten(1000); - // Make sure we get readyRead on server - QCOMPARE(serverSocket->waitForReadyRead(1000), true); + // Check for loopback, both from signal received and actual bytes returned + QCOMPARE(_multiSpy->waitForSignalByIndex(bytesReceivedSignalIndex, 1000), true); + QCOMPARE(_multiSpy->checkOnlySignalByMask(bytesReceivedSignalMask), true); + // Read the data and make sure it matches - QByteArray bytesIn = serverSocket->read(bytesOut.size() + 100); - QCOMPARE(bytesIn, bytesOut); + arguments = _multiSpy->getSpyByIndex(bytesReceivedSignalIndex)->takeFirst(); + QVERIFY(arguments.at(1).toByteArray() == bytesOut); + _multiSpy->clearAllSignals(); + // Disconnect the link _link->disconnect(); @@ -196,27 +191,21 @@ void TCPLinkUnitTest::_connectSucceed_test(void) QCOMPARE(_multiSpy->checkOnlySignalByMask(disconnectedSignalMask | connected2SignalMask), true); arguments = _multiSpy->getSpyByIndex(connected2SignalIndex)->takeFirst(); QCOMPARE(arguments.at(0).toBool(), false); - _multiSpy->clearSignalsByMask(disconnectedSignalMask); - - // Make sure we get disconnected signals from the server side - QCOMPARE(serverSocket->waitForDisconnected(1000), true ); + _multiSpy->clearAllSignals(); // Try to connect again to make sure everything was cleaned up correctly from previous connection // Connect to the server QCOMPARE(_link->connect(), true); - // Wait for the connection to come through on server side - QCOMPARE(server->waitForNewConnection(1000), true); - serverSocket = server->nextPendingConnection(); - Q_ASSERT(serverSocket); - // Make sure we get the two different connected signals QCOMPARE(_multiSpy->waitForSignalByIndex(connectedSignalIndex, 1000), true); QCOMPARE(_multiSpy->checkOnlySignalByMask(connectedSignalMask | connected2SignalMask), true); arguments = _multiSpy->getSpyByIndex(connected2SignalIndex)->takeFirst(); QCOMPARE(arguments.at(0).toBool(), true); - _multiSpy->clearSignalsByMask(connectedSignalMask); - + _multiSpy->clearAllSignals(); + + server->quit(); + QTest::qWait(500); // Wait a little for server thread to terminate delete server; } diff --git a/src/qgcunittest/TCPLinkTest.h b/src/qgcunittest/TCPLinkTest.h index 120fa96b14243727a02cb3f2d2138918cd71d343..61a0fa81dbb9ce6f4f273327b4cf2b61bd4575da 100644 --- a/src/qgcunittest/TCPLinkTest.h +++ b/src/qgcunittest/TCPLinkTest.h @@ -43,6 +43,10 @@ class TCPLinkUnitTest : public QObject public: TCPLinkUnitTest(void); + +signals: + void waitForBytesWritten(int msecs); + void waitForReadyRead(int msecs); private slots: void init(void); diff --git a/src/qgcunittest/TCPLoopBackServer.cc b/src/qgcunittest/TCPLoopBackServer.cc new file mode 100644 index 0000000000000000000000000000000000000000..07c1644f31061352ea97e8fd30bcc87b4ce3699a --- /dev/null +++ b/src/qgcunittest/TCPLoopBackServer.cc @@ -0,0 +1,65 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#include "TCPLoopBackServer.h" + +TCPLoopBackServer::TCPLoopBackServer(QHostAddress hostAddress, quint16 port) : + _hostAddress(hostAddress), + _port(port), + _tcpSocket(NULL) +{ + moveToThread(this); + start(HighPriority); +} + +void TCPLoopBackServer::run(void) +{ + // Start the server side + _tcpServer = new QTcpServer(this); + Q_CHECK_PTR(_tcpServer); + + bool connected = QObject::connect(_tcpServer, SIGNAL(newConnection()), this, SLOT(_newConnection())); + Q_ASSERT(connected); + + Q_ASSERT(_tcpServer->listen(_hostAddress, _port)); + + // Fall into main event loop + exec(); +} + +void TCPLoopBackServer::_newConnection(void) +{ + Q_ASSERT(_tcpServer); + _tcpSocket = _tcpServer->nextPendingConnection(); + Q_ASSERT(_tcpSocket); + bool connected = QObject::connect(_tcpSocket, SIGNAL(readyRead()), this, SLOT(_readBytes())); + Q_ASSERT(connected); +} + +void TCPLoopBackServer::_readBytes(void) +{ + Q_ASSERT(_tcpSocket); + QByteArray bytesIn = _tcpSocket->read(_tcpSocket->bytesAvailable()); + Q_ASSERT(_tcpSocket->write(bytesIn) == bytesIn.count()); + Q_ASSERT(_tcpSocket->waitForBytesWritten(1000)); +} diff --git a/src/qgcunittest/TCPLoopBackServer.h b/src/qgcunittest/TCPLoopBackServer.h new file mode 100644 index 0000000000000000000000000000000000000000..b433efc229ff964ddb9a399435048d62bdb6f873 --- /dev/null +++ b/src/qgcunittest/TCPLoopBackServer.h @@ -0,0 +1,55 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#ifndef TCPLOOPBACKSERVER_H +#define TCPLOOPBACKSERVER_H + +#include +#include +#include + +class TCPLoopBackServer : public QThread +{ + Q_OBJECT + +public: + TCPLoopBackServer(QHostAddress hostAddress, quint16 port); + +signals: + void newConnection(void); + +protected: + virtual void run(void); + +private slots: + void _newConnection(void); + void _readBytes(void); + +private: + QHostAddress _hostAddress; + quint16 _port; + QTcpServer* _tcpServer; + QTcpSocket* _tcpSocket; +}; + +#endif \ No newline at end of file