|
|
|
@ -21,37 +21,21 @@
@@ -21,37 +21,21 @@
|
|
|
|
|
|
|
|
|
|
======================================================================*/ |
|
|
|
|
|
|
|
|
|
#include "FileManagerTest.h" |
|
|
|
|
|
|
|
|
|
/// @file
|
|
|
|
|
/// @brief FileManager unit test. Note: All code here assumes all work between
|
|
|
|
|
/// the unit test, mack mavlink file server and file manager is happening on
|
|
|
|
|
/// the same thread.
|
|
|
|
|
///
|
|
|
|
|
/// @author Don Gagne <don@thegagnes.com>
|
|
|
|
|
|
|
|
|
|
#include "FileManagerTest.h" |
|
|
|
|
#include "UASManager.h" |
|
|
|
|
|
|
|
|
|
UT_REGISTER_TEST(FileManagerTest) |
|
|
|
|
|
|
|
|
|
FileManagerTest::FileManagerTest(void) : |
|
|
|
|
_mockFileServer(_systemIdQGC, _systemIdServer), |
|
|
|
|
_mockLink(NULL), |
|
|
|
|
_fileServer(NULL), |
|
|
|
|
_fileManager(NULL), |
|
|
|
|
_multiSpy(NULL) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Called once before all test cases are run
|
|
|
|
|
void FileManagerTest::initTestCase(void) |
|
|
|
|
{ |
|
|
|
|
_mockUAS = new MockUAS(); |
|
|
|
|
Q_CHECK_PTR(_mockUAS); |
|
|
|
|
|
|
|
|
|
_mockUAS->setMockSystemId(_systemIdServer); |
|
|
|
|
_mockUAS->setMockMavlinkPlugin(&_mockFileServer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FileManagerTest::cleanupTestCase(void) |
|
|
|
|
{ |
|
|
|
|
delete _mockUAS; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Called before every test case
|
|
|
|
@ -59,26 +43,37 @@ void FileManagerTest::init(void)
@@ -59,26 +43,37 @@ void FileManagerTest::init(void)
|
|
|
|
|
{ |
|
|
|
|
UnitTest::init(); |
|
|
|
|
|
|
|
|
|
Q_ASSERT(_multiSpy == NULL); |
|
|
|
|
_mockLink = new MockLink(); |
|
|
|
|
Q_CHECK_PTR(_mockLink); |
|
|
|
|
LinkManager::instance()->_addLink(_mockLink); |
|
|
|
|
LinkManager::instance()->connectLink(_mockLink); |
|
|
|
|
|
|
|
|
|
_fileServer = _mockLink->getFileServer(); |
|
|
|
|
QVERIFY(_fileServer != NULL); |
|
|
|
|
|
|
|
|
|
_fileManager = new FileManager(NULL, _mockUAS, _systemIdQGC); |
|
|
|
|
Q_CHECK_PTR(_fileManager); |
|
|
|
|
// Wait or the UAS to show up
|
|
|
|
|
UASManagerInterface* uasManager = UASManager::instance(); |
|
|
|
|
QSignalSpy spyUasCreate(uasManager, SIGNAL(UASCreated(UASInterface*))); |
|
|
|
|
if (!uasManager->getActiveUAS()) { |
|
|
|
|
QCOMPARE(spyUasCreate.wait(10000), true); |
|
|
|
|
} |
|
|
|
|
UASInterface* uas = uasManager->getActiveUAS(); |
|
|
|
|
QVERIFY(uas != NULL); |
|
|
|
|
|
|
|
|
|
_fileManager = uas->getFileManager(); |
|
|
|
|
QVERIFY(_fileManager != NULL); |
|
|
|
|
|
|
|
|
|
Q_ASSERT(_multiSpy == NULL); |
|
|
|
|
|
|
|
|
|
// Reset any internal state back to normal
|
|
|
|
|
_mockFileServer.setErrorMode(MockMavlinkFileServer::errModeNone); |
|
|
|
|
_fileServer->setErrorMode(MockLinkFileServer::errModeNone); |
|
|
|
|
_fileListReceived.clear(); |
|
|
|
|
|
|
|
|
|
connect(&_mockFileServer, &MockMavlinkFileServer::messageReceived, _fileManager, &FileManager::receiveMessage); |
|
|
|
|
|
|
|
|
|
connect(_fileManager, &FileManager::listEntry, this, &FileManagerTest::listEntry); |
|
|
|
|
|
|
|
|
|
_rgSignals[listEntrySignalIndex] = SIGNAL(listEntry(const QString&)); |
|
|
|
|
_rgSignals[listCompleteSignalIndex] = SIGNAL(listComplete(void)); |
|
|
|
|
|
|
|
|
|
_rgSignals[downloadFileLengthSignalIndex] = SIGNAL(downloadFileLength(unsigned int)); |
|
|
|
|
_rgSignals[downloadFileCompleteSignalIndex] = SIGNAL(downloadFileComplete(void)); |
|
|
|
|
|
|
|
|
|
_rgSignals[errorMessageSignalIndex] = SIGNAL(errorMessage(const QString&)); |
|
|
|
|
_rgSignals[commandCompleteSignalIndex] = SIGNAL(commandComplete(void)); |
|
|
|
|
_rgSignals[commandErrorSignalIndex] = SIGNAL(commandError(const QString&)); |
|
|
|
|
|
|
|
|
|
_multiSpy = new MultiSignalSpy(); |
|
|
|
|
Q_CHECK_PTR(_multiSpy); |
|
|
|
@ -91,10 +86,15 @@ void FileManagerTest::cleanup(void)
@@ -91,10 +86,15 @@ void FileManagerTest::cleanup(void)
|
|
|
|
|
Q_ASSERT(_multiSpy); |
|
|
|
|
Q_ASSERT(_fileManager); |
|
|
|
|
|
|
|
|
|
delete _fileManager; |
|
|
|
|
// Disconnecting the link will prompt for log file save
|
|
|
|
|
setExpectedFileDialog(getSaveFileName, QStringList()); |
|
|
|
|
LinkManager::instance()->disconnectLink(_mockLink); |
|
|
|
|
_fileServer = NULL; |
|
|
|
|
_mockLink = NULL; |
|
|
|
|
_fileManager = NULL; |
|
|
|
|
|
|
|
|
|
delete _multiSpy; |
|
|
|
|
|
|
|
|
|
_fileManager = NULL; |
|
|
|
|
_multiSpy = NULL; |
|
|
|
|
|
|
|
|
|
UnitTest::cleanup(); |
|
|
|
@ -108,7 +108,6 @@ void FileManagerTest::listEntry(const QString& entry)
@@ -108,7 +108,6 @@ void FileManagerTest::listEntry(const QString& entry)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
void FileManagerTest::_ackTest(void) |
|
|
|
|
{ |
|
|
|
|
Q_ASSERT(_fileManager); |
|
|
|
@ -122,16 +121,17 @@ void FileManagerTest::_ackTest(void)
@@ -122,16 +121,17 @@ void FileManagerTest::_ackTest(void)
|
|
|
|
|
QVERIFY(_multiSpy->checkNoSignals()); |
|
|
|
|
|
|
|
|
|
// Setup for no response from ack. This should cause a timeout error
|
|
|
|
|
_mockFileServer.setErrorMode(MockMavlinkFileServer::errModeNoResponse); |
|
|
|
|
_fileServer->setErrorMode(MockLinkFileServer::errModeNoResponse); |
|
|
|
|
QVERIFY(_fileManager->_sendCmdTestAck()); |
|
|
|
|
QTest::qWait(_ackTimerTimeoutMsecs); // Let the file manager timeout
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true); |
|
|
|
|
_multiSpy->waitForSignalByIndex(commandErrorSignalIndex, _ackTimerTimeoutMsecs); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
|
|
|
|
|
// Setup for a bad sequence number in the ack. This should cause an error;
|
|
|
|
|
_mockFileServer.setErrorMode(MockMavlinkFileServer::errModeBadSequence); |
|
|
|
|
_fileServer->setErrorMode(MockLinkFileServer::errModeBadSequence); |
|
|
|
|
QVERIFY(_fileManager->_sendCmdTestAck()); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true); |
|
|
|
|
_multiSpy->waitForSignalByIndex(commandErrorSignalIndex, _ackTimerTimeoutMsecs); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -144,19 +144,7 @@ void FileManagerTest::_noAckTest(void)
@@ -144,19 +144,7 @@ void FileManagerTest::_noAckTest(void)
|
|
|
|
|
// This should not get the ack back and timeout.
|
|
|
|
|
QVERIFY(_fileManager->_sendCmdTestNoAck()); |
|
|
|
|
QTest::qWait(_ackTimerTimeoutMsecs); // Let the file manager timeout
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FileManagerTest::_resetTest(void) |
|
|
|
|
{ |
|
|
|
|
Q_ASSERT(_fileManager); |
|
|
|
|
Q_ASSERT(_multiSpy); |
|
|
|
|
Q_ASSERT(_multiSpy->checkNoSignals() == true); |
|
|
|
|
|
|
|
|
|
// Send a reset command
|
|
|
|
|
// We should not get any signals back from this
|
|
|
|
|
QVERIFY(_fileManager->_sendCmdReset()); |
|
|
|
|
QVERIFY(_multiSpy->checkNoSignals()); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FileManagerTest::_listTest(void) |
|
|
|
@ -167,37 +155,49 @@ void FileManagerTest::_listTest(void)
@@ -167,37 +155,49 @@ void FileManagerTest::_listTest(void)
|
|
|
|
|
|
|
|
|
|
// FileManager::listDirectory signalling as follows:
|
|
|
|
|
// Emits a listEntry signal for each list entry
|
|
|
|
|
// Emits an errorMessage signal if:
|
|
|
|
|
// Emits an commandError signal if:
|
|
|
|
|
// It gets a Nak back
|
|
|
|
|
// Sequence number is incorrrect on any response
|
|
|
|
|
// CRC is incorrect on any responses
|
|
|
|
|
// List entry is formatted incorrectly
|
|
|
|
|
// It is possible to get a number of good listEntry signals, followed by an errorMessage signal
|
|
|
|
|
// Emits listComplete after it receives the final list entry
|
|
|
|
|
// If an errorMessage signal is signalled no listComplete is signalled
|
|
|
|
|
// It is possible to get a number of good listEntry signals, followed by an commandError signal
|
|
|
|
|
// Emits commandComplete after it receives the final list entry
|
|
|
|
|
// If an commandError signal is signalled no listComplete is signalled
|
|
|
|
|
|
|
|
|
|
// Send a bogus path
|
|
|
|
|
// We should get a single resetStatusMessages signal
|
|
|
|
|
// We should get a single errorMessage signal
|
|
|
|
|
// We should get a single commandError signal
|
|
|
|
|
_fileManager->listDirectory("/bogus"); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true); |
|
|
|
|
_multiSpy->waitForSignalByIndex(commandErrorSignalIndex, _ackTimerTimeoutMsecs); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
|
|
|
|
|
// Setup the mock file server with a valid directory list
|
|
|
|
|
QStringList fileList; |
|
|
|
|
fileList << "Ddir" << "Ffoo" << "Fbar"; |
|
|
|
|
_mockFileServer.setFileList(fileList); |
|
|
|
|
_fileServer->setFileList(fileList); |
|
|
|
|
|
|
|
|
|
// Send a list command at the root of the directory tree which should succeed
|
|
|
|
|
_fileManager->listDirectory("/"); |
|
|
|
|
QTest::qWait(_ackTimerTimeoutMsecs); // Let the file manager timeout
|
|
|
|
|
QCOMPARE(_multiSpy->checkSignalByMask(commandCompleteSignalMask), true); |
|
|
|
|
QCOMPARE(_multiSpy->checkNoSignalByMask(commandErrorSignalMask), true); |
|
|
|
|
QCOMPARE(_multiSpy->getSpyByIndex(listEntrySignalIndex)->count(), fileList.count()); |
|
|
|
|
QVERIFY(_fileListReceived == fileList); |
|
|
|
|
|
|
|
|
|
// Set everything back to initial state
|
|
|
|
|
_fileListReceived.clear(); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
|
|
|
|
|
// Run through the various server side failure modes
|
|
|
|
|
for (size_t i=0; i<MockMavlinkFileServer::cFailureModes; i++) { |
|
|
|
|
MockMavlinkFileServer::ErrorMode_t errMode = MockMavlinkFileServer::rgFailureModes[i]; |
|
|
|
|
for (size_t i=0; i<MockLinkFileServer::cFailureModes; i++) { |
|
|
|
|
MockLinkFileServer::ErrorMode_t errMode = MockLinkFileServer::rgFailureModes[i]; |
|
|
|
|
qDebug() << "Testing failure mode:" << errMode; |
|
|
|
|
_mockFileServer.setErrorMode(errMode); |
|
|
|
|
_fileServer->setErrorMode(errMode); |
|
|
|
|
|
|
|
|
|
_fileManager->listDirectory("/"); |
|
|
|
|
QTest::qWait(_ackTimerTimeoutMsecs); // Let the file manager timeout
|
|
|
|
|
|
|
|
|
|
if (errMode == MockMavlinkFileServer::errModeNoSecondResponse || errMode == MockMavlinkFileServer::errModeNakSecondResponse) { |
|
|
|
|
if (errMode == MockLinkFileServer::errModeNoSecondResponse || errMode == MockLinkFileServer::errModeNakSecondResponse) { |
|
|
|
|
// For simulated server errors on subsequent Acks, the first Ack will go through. This means we should have gotten some
|
|
|
|
|
// partial results. In the case of the directory list test set, all entries fit into the first ack, so we should have
|
|
|
|
|
// gotten back all of them.
|
|
|
|
@ -205,262 +205,193 @@ void FileManagerTest::_listTest(void)
@@ -205,262 +205,193 @@ void FileManagerTest::_listTest(void)
|
|
|
|
|
_multiSpy->clearSignalByIndex(listEntrySignalIndex); |
|
|
|
|
|
|
|
|
|
// And then it should have errored out because the next list Request would have failed.
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
} else { |
|
|
|
|
// For the simulated errors which failed the intial response we should not have gotten any results back at all.
|
|
|
|
|
// Just an error.
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Set everything back to initial state
|
|
|
|
|
_fileListReceived.clear(); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
_mockFileServer.setErrorMode(MockMavlinkFileServer::errModeNone); |
|
|
|
|
_fileServer->setErrorMode(MockLinkFileServer::errModeNone); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Send a list command at the root of the directory tree which should succeed
|
|
|
|
|
_fileManager->listDirectory("/"); |
|
|
|
|
QCOMPARE(_multiSpy->checkSignalByMask(listCompleteSignalMask), true); |
|
|
|
|
QCOMPARE(_multiSpy->checkNoSignalByMask(errorMessageSignalMask), true); |
|
|
|
|
QCOMPARE(_multiSpy->getSpyByIndex(listEntrySignalIndex)->count(), fileList.count()); |
|
|
|
|
QVERIFY(_fileListReceived == fileList); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
// Trying to write test code for read and burst mode download as well as implement support in MockLineFileServer reached a point
|
|
|
|
|
// of diminishing returns where the test code and mock server were generating more bugs in themselves than finding problems.
|
|
|
|
|
void FileManagerTest::_readDownloadTest(void) |
|
|
|
|
{ |
|
|
|
|
Q_ASSERT(_fileManager); |
|
|
|
|
Q_ASSERT(_multiSpy); |
|
|
|
|
Q_ASSERT(_multiSpy->checkNoSignals() == true); |
|
|
|
|
|
|
|
|
|
// FileManager::downloadPath works as follows:
|
|
|
|
|
// Sends an Open Command to the server
|
|
|
|
|
// Expects an Ack Response back from the server with the correct sequence numner
|
|
|
|
|
// Emits an errorMessage signal if it gets a Nak back
|
|
|
|
|
// Emits an downloadFileLength signal with the file length if it gets back a good Ack
|
|
|
|
|
// Sends subsequent Read commands to the server until it gets the full file contents back
|
|
|
|
|
// Emits a downloadFileProgress for each read command ack it gets back
|
|
|
|
|
// Sends Terminate command to server when download is complete to close Open command
|
|
|
|
|
// Mock file server will signal terminateCommandReceived when it gets a Terminate command
|
|
|
|
|
// Sends downloadFileComplete signal to indicate the download is complete
|
|
|
|
|
// Emits an errorMessage signal if sequence number is incorrrect on any response
|
|
|
|
|
// Emits an errorMessage signal if CRC is incorrect on any responses
|
|
|
|
|
|
|
|
|
|
// Expected signals if the Open command fails for any reason
|
|
|
|
|
quint16 signalMaskOpenFailure = errorMessageSignalMask; |
|
|
|
|
|
|
|
|
|
// Expected signals if the Read command fails for any reason
|
|
|
|
|
quint16 signalMaskReadFailure = downloadFileLengthSignalMask | errorMessageSignalMask; |
|
|
|
|
// We setup a spy on the Reset command signal of the mock file server so that we can determine that a
|
|
|
|
|
// Reset command was correctly sent after the Open/Read commands complete.
|
|
|
|
|
QSignalSpy resetSpy(_fileServer, SIGNAL(resetCommandReceived())); |
|
|
|
|
|
|
|
|
|
// Expected signals if the downloadPath command succeeds
|
|
|
|
|
quint16 signalMaskDownloadSuccess = downloadFileLengthSignalMask | downloadFileCompleteSignalMask; |
|
|
|
|
|
|
|
|
|
// Send a bogus path
|
|
|
|
|
// We should get a single resetStatusMessages signal
|
|
|
|
|
// We should get a single errorMessage signal
|
|
|
|
|
_fileManager->downloadPath("bogus", QDir::temp()); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskOpenFailure), true); |
|
|
|
|
_multiSpy->waitForSignalByIndex(commandErrorSignalIndex, _ackTimerTimeoutMsecs); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
|
|
|
|
|
QCOMPARE(resetSpy.count(), 0); |
|
|
|
|
|
|
|
|
|
// Clean previous downloads
|
|
|
|
|
for (size_t i=0; i<MockMavlinkFileServer::cFileTestCases; i++) { |
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(MockMavlinkFileServer::rgFileTestCases[i].filename); |
|
|
|
|
for (size_t i=0; i<MockLinkFileServer::cFileTestCases; i++) { |
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(MockLinkFileServer::rgFileTestCases[i].filename); |
|
|
|
|
if (QFile::exists(filePath)) { |
|
|
|
|
Q_ASSERT(QFile::remove(filePath)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// We setup a spy on the Terminate command signal of the mock file server so that we can determine that a
|
|
|
|
|
// Terminate command was correctly sent after the Open/Read commands complete.
|
|
|
|
|
QSignalSpy terminateSpy(&_mockFileServer, SIGNAL(terminateCommandReceived())); |
|
|
|
|
|
|
|
|
|
// Run through the set of file test cases
|
|
|
|
|
for (size_t i=0; i<MockMavlinkFileServer::cFileTestCases; i++) { |
|
|
|
|
const MockMavlinkFileServer::FileTestCase* testCase = &MockMavlinkFileServer::rgFileTestCases[i]; |
|
|
|
|
for (size_t i=0; i<MockLinkFileServer::cFileTestCases; i++) { |
|
|
|
|
const MockLinkFileServer::FileTestCase* testCase = &MockLinkFileServer::rgFileTestCases[i]; |
|
|
|
|
|
|
|
|
|
// Run through the various failure modes for this test case
|
|
|
|
|
for (size_t j=0; j<MockMavlinkFileServer::cFailureModes; j++) { |
|
|
|
|
for (size_t j=0; j<MockLinkFileServer::cFailureModes; j++) { |
|
|
|
|
qDebug() << "Testing successful download"; |
|
|
|
|
|
|
|
|
|
MockMavlinkFileServer::ErrorMode_t errMode = MockMavlinkFileServer::rgFailureModes[j]; |
|
|
|
|
// Run what should be a successful file download test case. No servers errors are being simulated.
|
|
|
|
|
_fileServer->setErrorMode(MockLinkFileServer::errModeNone); |
|
|
|
|
_fileManager->downloadPath(testCase->filename, QDir::temp()); |
|
|
|
|
QTest::qWait(_ackTimerTimeoutMsecs); // Let the file manager timeout
|
|
|
|
|
|
|
|
|
|
// This should be a succesful download
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandCompleteSignalMask), true); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
|
|
|
|
|
// We should get a single Reset command to close the session
|
|
|
|
|
QCOMPARE(resetSpy.count(), 1); |
|
|
|
|
resetSpy.clear(); |
|
|
|
|
|
|
|
|
|
// Validate file contents
|
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(MockLinkFileServer::rgFileTestCases[i].filename); |
|
|
|
|
_validateFileContents(filePath, MockLinkFileServer::rgFileTestCases[i].length); |
|
|
|
|
MockLinkFileServer::ErrorMode_t errMode = MockLinkFileServer::rgFailureModes[j]; |
|
|
|
|
|
|
|
|
|
qDebug() << "Testing failure mode:" << errMode; |
|
|
|
|
_mockFileServer.setErrorMode(errMode); |
|
|
|
|
_fileServer->setErrorMode(errMode); |
|
|
|
|
|
|
|
|
|
_fileManager->downloadPath(testCase->filename, QDir::temp()); |
|
|
|
|
QTest::qWait(_ackTimerTimeoutMsecs); // Let the file manager timeout
|
|
|
|
|
|
|
|
|
|
if (errMode == MockMavlinkFileServer::errModeNoSecondResponse || errMode == MockMavlinkFileServer::errModeNakSecondResponse) { |
|
|
|
|
// For simulated server errors on subsequent Acks, the first Ack will go through. We must handle things differently depending
|
|
|
|
|
// on whether the downloaded file requires multiple packets to complete the download.
|
|
|
|
|
if (testCase->fMultiPacketResponse) { |
|
|
|
|
// The downloaded file requires multiple Acks to complete. Hence first Read should have succeeded and sent one downloadFileComplete.
|
|
|
|
|
// Second Read should have failed.
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskReadFailure), true); |
|
|
|
|
|
|
|
|
|
// Open command succeeded, so we should get a Terminate for the open
|
|
|
|
|
QCOMPARE(terminateSpy.count(), 1); |
|
|
|
|
} else { |
|
|
|
|
if (errMode == MockLinkFileServer::errModeNakResponse) { |
|
|
|
|
// This will Nak the Open call which will fail the download, but not cause a Reset
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
QCOMPARE(resetSpy.count(), 0); |
|
|
|
|
} else { |
|
|
|
|
if (testCase->packetCount == 1 && (errMode == MockLinkFileServer::errModeNoSecondResponse || errMode == MockLinkFileServer::errModeNakSecondResponse)) { |
|
|
|
|
// The downloaded file fits within a single Ack response, hence there is no second Read issued.
|
|
|
|
|
// This should result in a successful download.
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskDownloadSuccess), true); |
|
|
|
|
|
|
|
|
|
// We should get a single Terminate command to close the Open session
|
|
|
|
|
QCOMPARE(terminateSpy.count(), 1); |
|
|
|
|
// This should result in a successful download, followed by a Reset
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandCompleteSignalMask), true); |
|
|
|
|
QCOMPARE(resetSpy.count(), 1); |
|
|
|
|
|
|
|
|
|
// Validate file contents
|
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(testCase->filename); |
|
|
|
|
_validateFileContents(filePath, testCase->length); |
|
|
|
|
} else { |
|
|
|
|
// Download should have failed, followed by a aReset
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
QCOMPARE(resetSpy.count(), 1); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// For all the other simulated server errors the Open command should have failed. Since the Open failed
|
|
|
|
|
// there is no session to terminate, hence no Terminate in this case.
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskOpenFailure), true); |
|
|
|
|
QCOMPARE(terminateSpy.count(), 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Cleanup for next iteration
|
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
terminateSpy.clear(); |
|
|
|
|
_mockFileServer.setErrorMode(MockMavlinkFileServer::errModeNone); |
|
|
|
|
resetSpy.clear(); |
|
|
|
|
_fileServer->setErrorMode(MockLinkFileServer::errModeNone); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Run what should be a successful file download test case. No servers errors are being simulated.
|
|
|
|
|
_mockFileServer.setErrorMode(MockMavlinkFileServer::errModeNone); |
|
|
|
|
_fileManager->downloadPath(testCase->filename, QDir::temp()); |
|
|
|
|
|
|
|
|
|
// This should be a succesful download
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskDownloadSuccess), true); |
|
|
|
|
|
|
|
|
|
// Make sure the file length coming back through the openFileLength signal is correct
|
|
|
|
|
QVERIFY(_multiSpy->getSpyByIndex(downloadFileLengthSignalIndex)->takeFirst().at(0).toInt() == testCase->length); |
|
|
|
|
|
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
|
|
|
|
|
// We should get a single Terminate command to close the session
|
|
|
|
|
QCOMPARE(terminateSpy.count(), 1); |
|
|
|
|
terminateSpy.clear(); |
|
|
|
|
|
|
|
|
|
// Validate file contents
|
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(MockMavlinkFileServer::rgFileTestCases[i].filename); |
|
|
|
|
_validateFileContents(filePath, MockMavlinkFileServer::rgFileTestCases[i].length); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
void FileManagerTest::_streamDownloadTest(void) |
|
|
|
|
{ |
|
|
|
|
Q_ASSERT(_fileManager); |
|
|
|
|
Q_ASSERT(_multiSpy); |
|
|
|
|
Q_ASSERT(_multiSpy->checkNoSignals() == true); |
|
|
|
|
|
|
|
|
|
// FileManager::streamPath works as follows:
|
|
|
|
|
// Sends an Open Command to the server
|
|
|
|
|
// Expects an Ack Response back from the server with the correct sequence numner
|
|
|
|
|
// Emits an errorMessage signal if it gets a Nak back
|
|
|
|
|
// Emits an downloadFileLength signal with the file length if it gets back a good Ack
|
|
|
|
|
// Sends a single Stream command to the server
|
|
|
|
|
// Expects continuous Ack responses back with file contents
|
|
|
|
|
// Emits a downloadFileProgress for each ack it gets back
|
|
|
|
|
// Sends Terminate command to server when download is complete to close Open command
|
|
|
|
|
// Mock file server will signal terminateCommandReceived when it gets a Terminate command
|
|
|
|
|
// Sends downloadFileComplete signal to indicate the download is complete
|
|
|
|
|
// Emits an errorMessage signal if sequence number is incorrrect on any response
|
|
|
|
|
// Emits an errorMessage signal if CRC is incorrect on any responses
|
|
|
|
|
|
|
|
|
|
// Expected signals if the Open command fails for any reason
|
|
|
|
|
quint16 signalMaskOpenFailure = errorMessageSignalMask; |
|
|
|
|
|
|
|
|
|
// Expected signals if the Read command fails for any reason
|
|
|
|
|
quint16 signalMaskReadFailure = downloadFileLengthSignalMask | errorMessageSignalMask; |
|
|
|
|
|
|
|
|
|
// Expected signals if the downloadPath command succeeds
|
|
|
|
|
quint16 signalMaskDownloadSuccess = downloadFileLengthSignalMask | downloadFileCompleteSignalMask; |
|
|
|
|
|
|
|
|
|
// Send a bogus path
|
|
|
|
|
// We should get a single resetStatusMessages signal
|
|
|
|
|
// We should get a single errorMessage signal
|
|
|
|
|
_fileManager->streamPath("bogus", QDir::temp()); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskOpenFailure), true); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
|
|
|
|
|
// Clean previous downloads
|
|
|
|
|
for (size_t i=0; i<MockMavlinkFileServer::cFileTestCases; i++) { |
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(MockMavlinkFileServer::rgFileTestCases[i].filename); |
|
|
|
|
if (QFile::exists(filePath)) { |
|
|
|
|
Q_ASSERT(QFile::remove(filePath)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// We setup a spy on the Terminate command signal of the mock file server so that we can determine that a
|
|
|
|
|
// Terminate command was correctly sent after the Open/Read commands complete.
|
|
|
|
|
QSignalSpy terminateSpy(&_mockFileServer, SIGNAL(terminateCommandReceived())); |
|
|
|
|
|
|
|
|
|
// Run through the set of file test cases
|
|
|
|
|
for (size_t i=0; i<MockMavlinkFileServer::cFileTestCases; i++) { |
|
|
|
|
const MockMavlinkFileServer::FileTestCase* testCase = &MockMavlinkFileServer::rgFileTestCases[i]; |
|
|
|
|
|
|
|
|
|
// Run through the various failure modes for this test case
|
|
|
|
|
for (size_t j=0; j<MockMavlinkFileServer::cFailureModes; j++) { |
|
|
|
|
|
|
|
|
|
MockMavlinkFileServer::ErrorMode_t errMode = MockMavlinkFileServer::rgFailureModes[j]; |
|
|
|
|
qDebug() << "Testing failure mode:" << errMode; |
|
|
|
|
_mockFileServer.setErrorMode(errMode); |
|
|
|
|
|
|
|
|
|
_fileManager->streamPath(testCase->filename, QDir::temp()); |
|
|
|
|
QTest::qWait(_ackTimerTimeoutMsecs); // Let the file manager timeout
|
|
|
|
|
|
|
|
|
|
if (errMode == MockMavlinkFileServer::errModeNoSecondResponse || errMode == MockMavlinkFileServer::errModeNakSecondResponse) { |
|
|
|
|
// For simulated server errors on subsequent Acks, the first Ack will go through. We must handle things differently depending
|
|
|
|
|
// on whether the downloaded file requires multiple packets to complete the download.
|
|
|
|
|
if (testCase->packetCount != 1) { |
|
|
|
|
// The downloaded file requires multiple Acks to complete. Second Ack should have failed.
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskReadFailure), true); |
|
|
|
|
|
|
|
|
|
// Open command succeeded, so we should get a Terminate for the open
|
|
|
|
|
QCOMPARE(terminateSpy.count(), 1); |
|
|
|
|
} else { |
|
|
|
|
// The downloaded file fits within a single Ack response, hence there is no second Read issued.
|
|
|
|
|
// This should result in a successful download.
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskDownloadSuccess), true); |
|
|
|
|
|
|
|
|
|
// We should get a single Terminate command to close the Open session
|
|
|
|
|
QCOMPARE(terminateSpy.count(), 1); |
|
|
|
|
|
|
|
|
|
// Validate file contents
|
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(testCase->filename); |
|
|
|
|
_validateFileContents(filePath, testCase->length); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// For all the other simulated server errors the Open command should have failed. Since the Open failed
|
|
|
|
|
// there is no session to terminate, hence no Terminate in this case.
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskOpenFailure), true); |
|
|
|
|
QCOMPARE(terminateSpy.count(), 0); |
|
|
|
|
} |
|
|
|
|
Q_ASSERT(_fileManager); |
|
|
|
|
Q_ASSERT(_multiSpy); |
|
|
|
|
Q_ASSERT(_multiSpy->checkNoSignals() == true); |
|
|
|
|
|
|
|
|
|
// We setup a spy on the Reset command signal of the mock file server so that we can determine that a
|
|
|
|
|
// Reset command was correctly sent after the Open/Read commands complete.
|
|
|
|
|
QSignalSpy resetSpy(_fileServer, SIGNAL(resetCommandReceived())); |
|
|
|
|
|
|
|
|
|
// Send a bogus path
|
|
|
|
|
_fileManager->streamPath("bogus", QDir::temp()); |
|
|
|
|
_multiSpy->waitForSignalByIndex(commandErrorSignalIndex, _ackTimerTimeoutMsecs); |
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
QCOMPARE(resetSpy.count(), 0); |
|
|
|
|
|
|
|
|
|
// Clean previous downloads
|
|
|
|
|
for (size_t i=0; i<MockLinkFileServer::cFileTestCases; i++) { |
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(MockLinkFileServer::rgFileTestCases[i].filename); |
|
|
|
|
if (QFile::exists(filePath)) { |
|
|
|
|
Q_ASSERT(QFile::remove(filePath)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Run through the set of file test cases
|
|
|
|
|
for (size_t i=0; i<MockLinkFileServer::cFileTestCases; i++) { |
|
|
|
|
const MockLinkFileServer::FileTestCase* testCase = &MockLinkFileServer::rgFileTestCases[i]; |
|
|
|
|
|
|
|
|
|
// Run through the various failure modes for this test case
|
|
|
|
|
for (size_t j=0; j<MockLinkFileServer::cFailureModes; j++) { |
|
|
|
|
qDebug() << "Testing successful download"; |
|
|
|
|
|
|
|
|
|
// Cleanup for next iteration
|
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
terminateSpy.clear(); |
|
|
|
|
_mockFileServer.setErrorMode(MockMavlinkFileServer::errModeNone); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Run what should be a successful file download test case. No servers errors are being simulated.
|
|
|
|
|
_mockFileServer.setErrorMode(MockMavlinkFileServer::errModeNone); |
|
|
|
|
_fileManager->streamPath(testCase->filename, QDir::temp()); |
|
|
|
|
|
|
|
|
|
// This should be a succesful download
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(signalMaskDownloadSuccess), true); |
|
|
|
|
|
|
|
|
|
// Make sure the file length coming back through the openFileLength signal is correct
|
|
|
|
|
QVERIFY(_multiSpy->getSpyByIndex(downloadFileLengthSignalIndex)->takeFirst().at(0).toInt() == testCase->length); |
|
|
|
|
|
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
|
|
|
|
|
// We should get a single Terminate command to close the session
|
|
|
|
|
QCOMPARE(terminateSpy.count(), 1); |
|
|
|
|
terminateSpy.clear(); |
|
|
|
|
|
|
|
|
|
// Validate file contents
|
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(MockMavlinkFileServer::rgFileTestCases[i].filename); |
|
|
|
|
_validateFileContents(filePath, MockMavlinkFileServer::rgFileTestCases[i].length); |
|
|
|
|
} |
|
|
|
|
// Run what should be a successful file download test case. No servers errors are being simulated.
|
|
|
|
|
_fileServer->setErrorMode(MockLinkFileServer::errModeNone); |
|
|
|
|
_fileManager->streamPath(testCase->filename, QDir::temp()); |
|
|
|
|
QTest::qWait(_ackTimerTimeoutMsecs); // Let the file manager timeout
|
|
|
|
|
|
|
|
|
|
// This should be a succesful download
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandCompleteSignalMask), true); |
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
|
|
|
|
|
// We should get a single Reset command to close the session
|
|
|
|
|
QCOMPARE(resetSpy.count(), 1); |
|
|
|
|
resetSpy.clear(); |
|
|
|
|
|
|
|
|
|
// Validate file contents
|
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(MockLinkFileServer::rgFileTestCases[i].filename); |
|
|
|
|
_validateFileContents(filePath, MockLinkFileServer::rgFileTestCases[i].length); |
|
|
|
|
MockLinkFileServer::ErrorMode_t errMode = MockLinkFileServer::rgFailureModes[j]; |
|
|
|
|
|
|
|
|
|
qDebug() << "Testing failure mode:" << errMode; |
|
|
|
|
_fileServer->setErrorMode(errMode); |
|
|
|
|
|
|
|
|
|
_fileManager->downloadPath(testCase->filename, QDir::temp()); |
|
|
|
|
QTest::qWait(_ackTimerTimeoutMsecs); // Let the file manager timeout
|
|
|
|
|
|
|
|
|
|
if (errMode == MockLinkFileServer::errModeNakResponse) { |
|
|
|
|
// This will Nak the Open call which will fail the download, but not cause a Reset
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
QCOMPARE(resetSpy.count(), 0); |
|
|
|
|
} else { |
|
|
|
|
if (testCase->packetCount == 1 && (errMode == MockLinkFileServer::errModeNoSecondResponse || errMode == MockLinkFileServer::errModeNakSecondResponse)) { |
|
|
|
|
// The downloaded file fits within a single Ack response, hence there is no second Read issued.
|
|
|
|
|
// This should result in a successful download, followed by a Reset
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandCompleteSignalMask), true); |
|
|
|
|
QCOMPARE(resetSpy.count(), 1); |
|
|
|
|
|
|
|
|
|
// Validate file contents
|
|
|
|
|
QString filePath = QDir::temp().absoluteFilePath(testCase->filename); |
|
|
|
|
_validateFileContents(filePath, testCase->length); |
|
|
|
|
} else { |
|
|
|
|
// Download should have failed, followed by a aReset
|
|
|
|
|
QCOMPARE(_multiSpy->checkOnlySignalByMask(commandErrorSignalMask), true); |
|
|
|
|
QCOMPARE(resetSpy.count(), 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Cleanup for next iteration
|
|
|
|
|
_multiSpy->clearAllSignals(); |
|
|
|
|
resetSpy.clear(); |
|
|
|
|
_fileServer->setErrorMode(MockLinkFileServer::errModeNone); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FileManagerTest::_validateFileContents(const QString& filePath, uint8_t length) |
|
|
|
@ -481,3 +412,4 @@ void FileManagerTest::_validateFileContents(const QString& filePath, uint8_t len
@@ -481,3 +412,4 @@ void FileManagerTest::_validateFileContents(const QString& filePath, uint8_t len
|
|
|
|
|
QCOMPARE((uint8_t)bytes[i], (uint8_t)(i & 0xFF)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|