14 changed files with 843 additions and 123 deletions
@ -0,0 +1,148 @@
@@ -0,0 +1,148 @@
|
||||
/*=====================================================================
|
||||
|
||||
QGroundControl Open Source Ground Control Station |
||||
|
||||
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
======================================================================*/ |
||||
|
||||
#include "MockMavlinkFileServer.h" |
||||
|
||||
void MockMavlinkFileServer::sendMessage(mavlink_message_t message) |
||||
{ |
||||
QGCUASFileManager::Request ackResponse; |
||||
QString path; |
||||
|
||||
Q_ASSERT(message.msgid == MAVLINK_MSG_ID_ENCAPSULATED_DATA); |
||||
|
||||
mavlink_encapsulated_data_t requestEncapsulatedData; |
||||
mavlink_msg_encapsulated_data_decode(&message, &requestEncapsulatedData); |
||||
QGCUASFileManager::Request* request = (QGCUASFileManager::Request*)&requestEncapsulatedData.data[0]; |
||||
|
||||
// Validate CRC
|
||||
if (request->hdr.crc32 != QGCUASFileManager::crc32(request)) { |
||||
_sendNak(QGCUASFileManager::kErrCrc); |
||||
} |
||||
|
||||
switch (request->hdr.opcode) { |
||||
case QGCUASFileManager::kCmdTestNoAck: |
||||
// ignored, ack not sent back, for testing only
|
||||
break; |
||||
|
||||
case QGCUASFileManager::kCmdReset: |
||||
// terminates all sessions
|
||||
// Fall through to send back Ack
|
||||
|
||||
case QGCUASFileManager::kCmdNone: |
||||
// ignored, always acked
|
||||
ackResponse.hdr.magic = 'f'; |
||||
ackResponse.hdr.opcode = QGCUASFileManager::kRspAck; |
||||
ackResponse.hdr.session = 0; |
||||
ackResponse.hdr.crc32 = 0; |
||||
ackResponse.hdr.size = 0; |
||||
_emitResponse(&ackResponse); |
||||
break; |
||||
|
||||
case QGCUASFileManager::kCmdList: |
||||
// We only support root path
|
||||
path = (char *)&request->data[0]; |
||||
if (!path.isEmpty() && path != "/") { |
||||
_sendNak(QGCUASFileManager::kErrNotDir); |
||||
break; |
||||
} |
||||
|
||||
if (request->hdr.offset > (uint32_t)_fileList.size()) { |
||||
_sendNak(QGCUASFileManager::kErrEOF); |
||||
break; |
||||
} |
||||
|
||||
ackResponse.hdr.magic = 'f'; |
||||
ackResponse.hdr.opcode = QGCUASFileManager::kRspAck; |
||||
ackResponse.hdr.session = 0; |
||||
ackResponse.hdr.size = 0; |
||||
|
||||
if (request->hdr.offset == 0) { |
||||
// Requesting first batch of file names
|
||||
Q_ASSERT(_fileList.size()); |
||||
char *bufPtr = (char *)&ackResponse.data[0]; |
||||
for (int i=0; i<_fileList.size(); i++) { |
||||
const char *filename = _fileList[i].toStdString().c_str(); |
||||
size_t cchFilename = strlen(filename); |
||||
strcpy(bufPtr, filename); |
||||
ackResponse.hdr.size += cchFilename + 1; |
||||
bufPtr += cchFilename + 1; |
||||
} |
||||
|
||||
// Final double termination
|
||||
*bufPtr = 0; |
||||
ackResponse.hdr.size++; |
||||
|
||||
} else { |
||||
// All filenames fit in first ack, send final null terminated ack
|
||||
ackResponse.data[0] = 0; |
||||
ackResponse.hdr.size = 1; |
||||
} |
||||
|
||||
_emitResponse(&ackResponse); |
||||
|
||||
break; |
||||
|
||||
// Remainder of commands are NYI
|
||||
|
||||
case QGCUASFileManager::kCmdTerminate: |
||||
// releases sessionID, closes file
|
||||
case QGCUASFileManager::kCmdOpen: |
||||
// opens <path> for reading, returns <session>
|
||||
case QGCUASFileManager::kCmdRead: |
||||
// reads <size> bytes from <offset> in <session>
|
||||
case QGCUASFileManager::kCmdCreate: |
||||
// creates <path> for writing, returns <session>
|
||||
case QGCUASFileManager::kCmdWrite: |
||||
// appends <size> bytes at <offset> in <session>
|
||||
case QGCUASFileManager::kCmdRemove: |
||||
// remove file (only if created by server?)
|
||||
default: |
||||
// nack for all NYI opcodes
|
||||
_sendNak(QGCUASFileManager::kErrUnknownCommand); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void MockMavlinkFileServer::_sendNak(QGCUASFileManager::ErrorCode error) |
||||
{ |
||||
QGCUASFileManager::Request nakResponse; |
||||
|
||||
nakResponse.hdr.magic = 'f'; |
||||
nakResponse.hdr.opcode = QGCUASFileManager::kRspNak; |
||||
nakResponse.hdr.session = 0; |
||||
nakResponse.hdr.size = sizeof(nakResponse.data[0]); |
||||
nakResponse.data[0] = error; |
||||
|
||||
_emitResponse(&nakResponse); |
||||
} |
||||
|
||||
void MockMavlinkFileServer::_emitResponse(QGCUASFileManager::Request* request) |
||||
{ |
||||
mavlink_message_t mavlinkMessage; |
||||
|
||||
request->hdr.crc32 = QGCUASFileManager::crc32(request); |
||||
|
||||
mavlink_msg_encapsulated_data_pack(250, 0, &mavlinkMessage, 0 /*_encdata_seq*/, (uint8_t*)request); |
||||
|
||||
emit messageReceived(NULL, mavlinkMessage); |
||||
} |
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
/*=====================================================================
|
||||
|
||||
QGroundControl Open Source Ground Control Station |
||||
|
||||
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
======================================================================*/ |
||||
|
||||
#ifndef MOCKMAVLINKFILESERVER_H |
||||
#define MOCKMAVLINKFILESERVER_H |
||||
|
||||
#include "MockMavlinkInterface.h" |
||||
#include "QGCUASFileManager.h" |
||||
|
||||
|
||||
#include <QStringList> |
||||
|
||||
class MockMavlinkFileServer : public MockMavlinkInterface |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
MockMavlinkFileServer(void) { }; |
||||
|
||||
void setFileList(QStringList& fileList) { _fileList = fileList; } |
||||
|
||||
// From MockMavlinkInterface
|
||||
virtual void sendMessage(mavlink_message_t message); |
||||
|
||||
private: |
||||
void _sendNak(QGCUASFileManager::ErrorCode error); |
||||
void _emitResponse(QGCUASFileManager::Request* request); |
||||
|
||||
QStringList _fileList; |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// MockMavlinkInterface.cc
|
||||
// QGroundControl
|
||||
//
|
||||
// Created by Donald Gagne on 6/19/14.
|
||||
// Copyright (c) 2014 Donald Gagne. All rights reserved.
|
||||
//
|
||||
|
||||
#include "MockMavlinkInterface.h" |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
/*=====================================================================
|
||||
|
||||
QGroundControl Open Source Ground Control Station |
||||
|
||||
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
======================================================================*/ |
||||
|
||||
#include <QObject> |
||||
|
||||
#include "QGCMAVLink.h" |
||||
#include "LinkInterface.h" |
||||
|
||||
#ifndef MOCKMAVLINKINTERFACE_H |
||||
#define MOCKMAVLINKINTERFACE_H |
||||
|
||||
class MockMavlinkInterface : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
virtual void sendMessage(mavlink_message_t message) = 0; |
||||
|
||||
signals: |
||||
// link argument will always be NULL
|
||||
void messageReceived(LinkInterface* link, mavlink_message_t message); |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,156 @@
@@ -0,0 +1,156 @@
|
||||
/*=====================================================================
|
||||
|
||||
QGroundControl Open Source Ground Control Station |
||||
|
||||
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
======================================================================*/ |
||||
|
||||
#include "QGCUASFileManagerTest.h" |
||||
|
||||
/// @file
|
||||
/// @brief QGCUASFileManager unit test
|
||||
///
|
||||
/// @author Don Gagne <don@thegagnes.com>
|
||||
|
||||
QGCUASFileManagerUnitTest::QGCUASFileManagerUnitTest(void) : |
||||
_fileManager(NULL), |
||||
_multiSpy(NULL) |
||||
{ |
||||
|
||||
} |
||||
|
||||
// Called once before all test cases are run
|
||||
void QGCUASFileManagerUnitTest::initTestCase(void) |
||||
{ |
||||
_mockUAS.setMockMavlinkPlugin(&_mockFileServer); |
||||
} |
||||
|
||||
// Called before every test case
|
||||
void QGCUASFileManagerUnitTest::init(void) |
||||
{ |
||||
Q_ASSERT(_multiSpy == NULL); |
||||
|
||||
_fileManager = new QGCUASFileManager(NULL, &_mockUAS); |
||||
Q_CHECK_PTR(_fileManager); |
||||
|
||||
bool connected = connect(&_mockFileServer, SIGNAL(messageReceived(LinkInterface*, mavlink_message_t)), _fileManager, SLOT(receiveMessage(LinkInterface*, mavlink_message_t))); |
||||
Q_ASSERT(connected); |
||||
|
||||
connected = connect(_fileManager, SIGNAL(statusMessage(const QString&)), this, SLOT(statusMessage(const QString&))); |
||||
Q_ASSERT(connected); |
||||
|
||||
_rgSignals[statusMessageSignalIndex] = SIGNAL(statusMessage(const QString&)); |
||||
_rgSignals[errorMessageSignalIndex] = SIGNAL(errorMessage(const QString&)); |
||||
_rgSignals[resetStatusMessagesSignalIndex] = SIGNAL(resetStatusMessages(void)); |
||||
|
||||
_multiSpy = new MultiSignalSpy(); |
||||
Q_CHECK_PTR(_multiSpy); |
||||
QCOMPARE(_multiSpy->init(_fileManager, _rgSignals, _cSignals), true); |
||||
} |
||||
|
||||
// Called after every test case
|
||||
void QGCUASFileManagerUnitTest::cleanup(void) |
||||
{ |
||||
Q_ASSERT(_multiSpy); |
||||
Q_ASSERT(_fileManager); |
||||
|
||||
delete _fileManager; |
||||
delete _multiSpy; |
||||
|
||||
_fileManager = NULL; |
||||
_multiSpy = NULL; |
||||
} |
||||
|
||||
/// @brief Connected to QGCUASFileManager statusMessage signal in order to catch list command output
|
||||
void QGCUASFileManagerUnitTest::statusMessage(const QString& msg) |
||||
{ |
||||
// Keep a list of all names received so we can test it for correctness
|
||||
_fileListReceived += msg; |
||||
} |
||||
|
||||
|
||||
void QGCUASFileManagerUnitTest::_ackTest(void) |
||||
{ |
||||
Q_ASSERT(_fileManager); |
||||
Q_ASSERT(_multiSpy); |
||||
Q_ASSERT(_multiSpy->checkNoSignals() == true); |
||||
|
||||
// If the file manager doesn't receive an ack it will timeout and emit an error. So make sure
|
||||
// we don't get any error signals.
|
||||
QVERIFY(_fileManager->_sendCmdTestAck()); |
||||
QVERIFY(_multiSpy->checkNoSignals()); |
||||
} |
||||
|
||||
void QGCUASFileManagerUnitTest::_noAckTest(void) |
||||
{ |
||||
Q_ASSERT(_fileManager); |
||||
Q_ASSERT(_multiSpy); |
||||
Q_ASSERT(_multiSpy->checkNoSignals() == true); |
||||
|
||||
// This should not get the ack back and timeout.
|
||||
QVERIFY(_fileManager->_sendCmdTestNoAck()); |
||||
QTest::qWait(2000); // Let the file manager timeout, magic number 2 secs must be larger than file manager ack timeout
|
||||
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask), true); |
||||
} |
||||
|
||||
void QGCUASFileManagerUnitTest::_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()); |
||||
} |
||||
|
||||
void QGCUASFileManagerUnitTest::_listTest(void) |
||||
{ |
||||
Q_ASSERT(_fileManager); |
||||
Q_ASSERT(_multiSpy); |
||||
Q_ASSERT(_multiSpy->checkNoSignals() == true); |
||||
|
||||
// Send a bogus path
|
||||
// We should get a single resetStatusMessages signal
|
||||
// We should get a single errorMessage signal
|
||||
_fileManager->listRecursively("/bogus"); |
||||
QCOMPARE(_multiSpy->checkOnlySignalByMask(errorMessageSignalMask | resetStatusMessagesSignalMask), true); |
||||
_multiSpy->clearAllSignals(); |
||||
|
||||
// Send a list command at the root of the directory tree
|
||||
// We should get back a single resetStatusMessages signal
|
||||
// We should not get back an errorMessage signal
|
||||
// We should get back one or more statusMessage signals
|
||||
// The returned list should match out inputs
|
||||
|
||||
QStringList fileList; |
||||
fileList << "Ddir" << "Ffoo" << "Fbar"; |
||||
_mockFileServer.setFileList(fileList); |
||||
|
||||
QStringList fileListExpected; |
||||
fileListExpected << "dir/" << "foo" << "bar"; |
||||
|
||||
_fileListReceived.clear(); |
||||
|
||||
_fileManager->listRecursively("/"); |
||||
QCOMPARE(_multiSpy->checkSignalByMask(resetStatusMessagesSignalMask), true); // We should be told to reset status messages
|
||||
QCOMPARE(_multiSpy->checkNoSignalByMask(errorMessageSignalMask), true); // We should not get an error signals
|
||||
QVERIFY(_fileListReceived == fileListExpected); |
||||
} |
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
/*=====================================================================
|
||||
|
||||
QGroundControl Open Source Ground Control Station |
||||
|
||||
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
======================================================================*/ |
||||
|
||||
#ifndef QGCUASFILEMANAGERTEST_H |
||||
#define QGCUASFILEMANAGERTEST_H |
||||
|
||||
#include <QObject> |
||||
#include <QtTest/QtTest> |
||||
|
||||
#include "AutoTest.h" |
||||
#include "MockUAS.h" |
||||
#include "MockMavlinkFileServer.h" |
||||
#include "QGCUASFileManager.h" |
||||
#include "MultiSignalSpy.h" |
||||
|
||||
/// @file
|
||||
/// @brief QGCUASFileManager unit test
|
||||
///
|
||||
/// @author Don Gagne <don@thegagnes.com>
|
||||
|
||||
class QGCUASFileManagerUnitTest : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
QGCUASFileManagerUnitTest(void); |
||||
|
||||
private slots: |
||||
// Test case initialization
|
||||
void initTestCase(void); |
||||
void init(void); |
||||
void cleanup(void); |
||||
|
||||
// Test cases
|
||||
void _ackTest(void); |
||||
void _noAckTest(void); |
||||
void _resetTest(void); |
||||
void _listTest(void); |
||||
|
||||
// Connected to QGCUASFileManager statusMessage signal
|
||||
void statusMessage(const QString&); |
||||
|
||||
private: |
||||
enum { |
||||
statusMessageSignalIndex = 0, |
||||
errorMessageSignalIndex, |
||||
resetStatusMessagesSignalIndex, |
||||
|
||||
maxSignalIndex |
||||
}; |
||||
|
||||
enum { |
||||
statusMessageSignalMask = 1 << statusMessageSignalIndex, |
||||
errorMessageSignalMask = 1 << errorMessageSignalIndex, |
||||
resetStatusMessagesSignalMask = 1 << resetStatusMessagesSignalIndex, |
||||
}; |
||||
|
||||
MockUAS _mockUAS; |
||||
MockMavlinkFileServer _mockFileServer; |
||||
|
||||
QGCUASFileManager* _fileManager; |
||||
|
||||
MultiSignalSpy* _multiSpy; |
||||
static const size_t _cSignals = maxSignalIndex; |
||||
const char* _rgSignals[_cSignals]; |
||||
|
||||
QStringList _fileListReceived; |
||||
}; |
||||
|
||||
DECLARE_TEST(QGCUASFileManagerUnitTest) |
||||
|
||||
#endif |
Loading…
Reference in new issue