MissionManagerTest.cc 14.5 KB
Newer Older
1 2 3 4 5 6 7 8 9
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

Don Gagne's avatar
Don Gagne committed
10 11 12 13 14 15

#include "MissionManagerTest.h"
#include "LinkManager.h"
#include "MultiVehicleManager.h"

const MissionManagerTest::TestCase_t MissionManagerTest::_rgTestCases[] = {
16
    { "0\t0\t3\t16\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n",  { 0, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_WAYPOINT,     10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT } },
Don Gagne's avatar
Don Gagne committed
17
    { "1\t0\t3\t17\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n",  { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LOITER_UNLIM, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT } },
18 19 20
    { "2\t0\t3\t18\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n",  { 2, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LOITER_TURNS, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT } },
    { "3\t0\t3\t19\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n",  { 3, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LOITER_TIME,  10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT } },
    { "4\t0\t3\t21\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n",  { 4, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LAND,         10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT } },
21
    { "6\t0\t2\t112\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n", { 5, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_CONDITION_DELAY,  10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_MISSION } },
Don Gagne's avatar
Don Gagne committed
22
};
Don Gagne's avatar
Don Gagne committed
23
const size_t MissionManagerTest::_cTestCases = sizeof(_rgTestCases)/sizeof(_rgTestCases[0]);
Don Gagne's avatar
Don Gagne committed
24 25 26 27 28 29

MissionManagerTest::MissionManagerTest(void)
{
    
}

30
void MissionManagerTest::_writeItems(MockLinkMissionItemHandler::FailureMode_t failureMode)
Don Gagne's avatar
Don Gagne committed
31
{
32
    _mockLink->setMissionItemFailureMode(failureMode);
33
    
Don Gagne's avatar
Don Gagne committed
34
    // Setup our test case data
35
    QList<MissionItem*> missionItems;
Don Gagne's avatar
Don Gagne committed
36
    
37
    // Editor has a home position item on the front, so we do the same
38 39
    MissionItem* homeItem = new MissionItem(NULL /* Vehicle */, this);
    homeItem->setCommand(MAV_CMD_NAV_WAYPOINT);
40
    homeItem->setCoordinate(QGeoCoordinate(47.3769, 8.549444, 0));
41
    homeItem->setSequenceNumber(0);
42
    missionItems.append(homeItem);
43

Don Gagne's avatar
Don Gagne committed
44
    for (size_t i=0; i<_cTestCases; i++) {
Don Gagne's avatar
Don Gagne committed
45 46
        const TestCase_t* testCase = &_rgTestCases[i];
        
47
        MissionItem* missionItem = new MissionItem(this);
Don Gagne's avatar
Don Gagne committed
48 49
        
        QTextStream loadStream(testCase->itemStream, QIODevice::ReadOnly);
50
        QVERIFY(missionItem->load(loadStream));
51 52

        // Mission Manager expects to get 1-base sequence numbers for write
53
        missionItem->setSequenceNumber(missionItem->sequenceNumber() + 1);
Don Gagne's avatar
Don Gagne committed
54
        
55
        missionItems.append(missionItem);
Don Gagne's avatar
Don Gagne committed
56 57 58
    }
    
    // Send the items to the vehicle
59
    _missionManager->writeMissionItems(missionItems);
60
    
61 62 63
    // writeMissionItems should emit these signals before returning:
    //      inProgressChanged
    //      newMissionItemsAvailable
Don Gagne's avatar
Don Gagne committed
64
    QVERIFY(_missionManager->inProgress());
65
    QCOMPARE(_multiSpyMissionManager->checkSignalByMask(inProgressChangedSignalMask | newMissionItemsAvailableSignalMask), true);
Don Gagne's avatar
Don Gagne committed
66 67
    _checkInProgressValues(true);
    
68
    _multiSpyMissionManager->clearAllSignals();
Don Gagne's avatar
Don Gagne committed
69
    
70 71 72 73 74
    if (failureMode == MockLinkMissionItemHandler::FailNone) {
        // This should be clean run
        
        // Wait for write sequence to complete. We should get:
        //      inProgressChanged(false) signal
75 76
        _multiSpyMissionManager->waitForSignalByIndex(inProgressChangedSignalIndex, _missionManagerSignalWaitTime);
        QCOMPARE(_multiSpyMissionManager->checkOnlySignalByMask(inProgressChangedSignalMask), true);
77 78 79 80
        
        // Validate inProgressChanged signal value
        _checkInProgressValues(false);

Don Gagne's avatar
Don Gagne committed
81 82 83 84 85 86 87 88
        // Validate item count in mission manager

        int expectedCount = (int)_cTestCases;
        if (_mockLink->getFirmwareType() == MAV_AUTOPILOT_ARDUPILOTMEGA) {
            // Home position at position 0 comes from vehicle
            expectedCount++;
        }

89
        QCOMPARE(_missionManager->missionItems().count(), expectedCount);
90 91 92
    } else {
        // This should be a failed run
        
Don Gagne's avatar
Don Gagne committed
93 94
        setExpectedMessageBox(QMessageBox::Ok);

95 96 97
        // Wait for write sequence to complete. We should get:
        //      inProgressChanged(false) signal
        //      error(errorCode, QString) signal
98 99
        _multiSpyMissionManager->waitForSignalByIndex(inProgressChangedSignalIndex, _missionManagerSignalWaitTime);
        QCOMPARE(_multiSpyMissionManager->checkSignalByMask(inProgressChangedSignalMask | errorSignalMask), true);
100 101 102 103 104
        
        // Validate inProgressChanged signal value
        _checkInProgressValues(false);
        
        // Validate error signal values
105
        QSignalSpy* spy = _multiSpyMissionManager->getSpyByIndex(errorSignalIndex);
106 107 108 109
        QList<QVariant> signalArgs = spy->takeFirst();
        QCOMPARE(signalArgs.count(), 2);
        qDebug() << signalArgs[1].toString();

Don Gagne's avatar
Don Gagne committed
110
        checkExpectedMessageBox();
111
    }
Don Gagne's avatar
Don Gagne committed
112
    
113
    _multiSpyMissionManager->clearAllSignals();
114 115
}

116
void MissionManagerTest::_roundTripItems(MockLinkMissionItemHandler::FailureMode_t failureMode)
117
{
118
    _writeItems(MockLinkMissionItemHandler::FailNone);
Don Gagne's avatar
Don Gagne committed
119
    
120
    _mockLink->setMissionItemFailureMode(failureMode);
121

Don Gagne's avatar
Don Gagne committed
122 123 124 125 126
    // Read the items back from the vehicle
    _missionManager->requestMissionItems();
    
    // requestMissionItems should emit inProgressChanged signal before returning so no need to wait for it
    QVERIFY(_missionManager->inProgress());
127
    QCOMPARE(_multiSpyMissionManager->checkOnlySignalByMask(inProgressChangedSignalMask), true);
Don Gagne's avatar
Don Gagne committed
128 129
    _checkInProgressValues(true);
    
130
    _multiSpyMissionManager->clearAllSignals();
Don Gagne's avatar
Don Gagne committed
131
    
132 133 134 135 136 137
    if (failureMode == MockLinkMissionItemHandler::FailNone) {
        // This should be clean run
        
        // Now wait for read sequence to complete. We should get:
        //      inProgressChanged(false) signal to signal completion
        //      newMissionItemsAvailable signal
138 139
        _multiSpyMissionManager->waitForSignalByIndex(inProgressChangedSignalIndex, _missionManagerSignalWaitTime);
        QCOMPARE(_multiSpyMissionManager->checkSignalByMask(newMissionItemsAvailableSignalMask | inProgressChangedSignalMask), true);
140
        _checkInProgressValues(false);
Don Gagne's avatar
Don Gagne committed
141

142 143 144
    } else {
        // This should be a failed run
        
Don Gagne's avatar
Don Gagne committed
145 146
        setExpectedMessageBox(QMessageBox::Ok);

147 148 149 150
        // Wait for read sequence to complete. We should get:
        //      inProgressChanged(false) signal to signal completion
        //      error(errorCode, QString) signal
        //      newMissionItemsAvailable signal
151 152
        _multiSpyMissionManager->waitForSignalByIndex(inProgressChangedSignalIndex, _missionManagerSignalWaitTime);
        QCOMPARE(_multiSpyMissionManager->checkSignalByMask(newMissionItemsAvailableSignalMask | inProgressChangedSignalMask | errorSignalMask), true);
153 154 155 156 157
        
        // Validate inProgressChanged signal value
        _checkInProgressValues(false);
        
        // Validate error signal values
158
        QSignalSpy* spy = _multiSpyMissionManager->getSpyByIndex(errorSignalIndex);
159 160 161
        QList<QVariant> signalArgs = spy->takeFirst();
        QCOMPARE(signalArgs.count(), 2);
        qDebug() << signalArgs[1].toString();
Don Gagne's avatar
Don Gagne committed
162 163
        
        checkExpectedMessageBox();
164
    }
Don Gagne's avatar
Don Gagne committed
165
    
166
    _multiSpyMissionManager->clearAllSignals();
167 168

    // Validate returned items
Don Gagne's avatar
Don Gagne committed
169
    
170
    size_t cMissionItemsExpected;
Don Gagne's avatar
Don Gagne committed
171
    
172
    if (failureMode == MockLinkMissionItemHandler::FailNone) {
Don Gagne's avatar
Don Gagne committed
173 174 175 176 177
        cMissionItemsExpected = (int)_cTestCases;
        if (_mockLink->getFirmwareType() == MAV_AUTOPILOT_ARDUPILOTMEGA) {
            // Home position at position 0 comes from vehicle
            cMissionItemsExpected++;
        }
178
    } else {
179
        cMissionItemsExpected = 0;
180 181
    }
    
182
    QCOMPARE(_missionManager->missionItems().count(), (int)cMissionItemsExpected);
Don Gagne's avatar
Don Gagne committed
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199

    size_t firstActualItem = 0;
    if (_mockLink->getFirmwareType() == MAV_AUTOPILOT_ARDUPILOTMEGA) {
        // First item is home position, don't validate it
        firstActualItem++;
    }

    int testCaseIndex = 0;
    for (size_t actualItemIndex=firstActualItem; actualItemIndex<cMissionItemsExpected; actualItemIndex++) {
        const TestCase_t* testCase = &_rgTestCases[testCaseIndex];

        int expectedSequenceNumber = testCase->expectedItem.sequenceNumber;
        if (_mockLink->getFirmwareType() == MAV_AUTOPILOT_ARDUPILOTMEGA) {
            // Account for home position in first item
            expectedSequenceNumber++;
        }

200
        MissionItem* actual = _missionManager->missionItems()[actualItemIndex];
Don Gagne's avatar
Don Gagne committed
201
        
Don Gagne's avatar
Don Gagne committed
202 203
        qDebug() << "Test case" << testCaseIndex;
        QCOMPARE(actual->sequenceNumber(),          expectedSequenceNumber);
Don Gagne's avatar
Don Gagne committed
204 205 206 207
        QCOMPARE(actual->coordinate().latitude(),   testCase->expectedItem.coordinate.latitude());
        QCOMPARE(actual->coordinate().longitude(),  testCase->expectedItem.coordinate.longitude());
        QCOMPARE(actual->coordinate().altitude(),   testCase->expectedItem.coordinate.altitude());
        QCOMPARE((int)actual->command(),       (int)testCase->expectedItem.command);
Don Gagne's avatar
Don Gagne committed
208
        QCOMPARE(actual->param1(),                  testCase->expectedItem.param1);
Don Gagne's avatar
Don Gagne committed
209 210 211 212 213
        QCOMPARE(actual->param2(),                  testCase->expectedItem.param2);
        QCOMPARE(actual->param3(),                  testCase->expectedItem.param3);
        QCOMPARE(actual->param4(),                  testCase->expectedItem.param4);
        QCOMPARE(actual->autoContinue(),            testCase->expectedItem.autocontinue);
        QCOMPARE(actual->frame(),                   testCase->expectedItem.frame);
Don Gagne's avatar
Don Gagne committed
214 215

        testCaseIndex++;
Don Gagne's avatar
Don Gagne committed
216
    }
217
    
Don Gagne's avatar
Don Gagne committed
218
}
219

Don Gagne's avatar
Don Gagne committed
220
void MissionManagerTest::_testWriteFailureHandlingWorker(void)
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
{
    /*
    /// Called to send a MISSION_ACK message while the MissionManager is in idle state
    void sendUnexpectedMissionAck(MAV_MISSION_RESULT ackType) { _missionItemHandler.sendUnexpectedMissionAck(ackType); }
    
    /// Called to send a MISSION_ITEM message while the MissionManager is in idle state
    void sendUnexpectedMissionItem(void) { _missionItemHandler.sendUnexpectedMissionItem(); }
    
    /// Called to send a MISSION_REQUEST message while the MissionManager is in idle state
    void sendUnexpectedMissionRequest(void) { _missionItemHandler.sendUnexpectedMissionRequest(); }
    */
    
    typedef struct {
        const char*                                 failureText;
        MockLinkMissionItemHandler::FailureMode_t   failureMode;
    } TestCase_t;
    
    static const TestCase_t rgTestCases[] = {
239 240 241 242 243 244 245 246 247 248
        { "No Failure",                         MockLinkMissionItemHandler::FailNone },
        { "FailWriteRequest0NoResponse",        MockLinkMissionItemHandler::FailWriteRequest0NoResponse },
        { "FailWriteRequest1NoResponse",        MockLinkMissionItemHandler::FailWriteRequest1NoResponse },
        { "FailWriteRequest0IncorrectSequence", MockLinkMissionItemHandler::FailWriteRequest0IncorrectSequence },
        { "FailWriteRequest1IncorrectSequence", MockLinkMissionItemHandler::FailWriteRequest1IncorrectSequence },
        { "FailWriteRequest0ErrorAck",          MockLinkMissionItemHandler::FailWriteRequest0ErrorAck },
        { "FailWriteRequest1ErrorAck",          MockLinkMissionItemHandler::FailWriteRequest1ErrorAck },
        { "FailWriteFinalAckNoResponse",        MockLinkMissionItemHandler::FailWriteFinalAckNoResponse },
        { "FailWriteFinalAckErrorAck",          MockLinkMissionItemHandler::FailWriteFinalAckErrorAck },
        { "FailWriteFinalAckMissingRequests",   MockLinkMissionItemHandler::FailWriteFinalAckMissingRequests },
249 250 251
    };

    for (size_t i=0; i<sizeof(rgTestCases)/sizeof(rgTestCases[0]); i++) {
252 253
        qDebug() << "TEST CASE " << rgTestCases[i].failureText;
        _writeItems(rgTestCases[i].failureMode);
254 255 256
        _mockLink->resetMissionItemHandler();
    }
}
257

Don Gagne's avatar
Don Gagne committed
258
void MissionManagerTest::_testReadFailureHandlingWorker(void)
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
{
    /*
     /// Called to send a MISSION_ACK message while the MissionManager is in idle state
     void sendUnexpectedMissionAck(MAV_MISSION_RESULT ackType) { _missionItemHandler.sendUnexpectedMissionAck(ackType); }
     
     /// Called to send a MISSION_ITEM message while the MissionManager is in idle state
     void sendUnexpectedMissionItem(void) { _missionItemHandler.sendUnexpectedMissionItem(); }
     
     /// Called to send a MISSION_REQUEST message while the MissionManager is in idle state
     void sendUnexpectedMissionRequest(void) { _missionItemHandler.sendUnexpectedMissionRequest(); }
     */
    
    typedef struct {
        const char*                                 failureText;
        MockLinkMissionItemHandler::FailureMode_t   failureMode;
    } TestCase_t;
    
    static const TestCase_t rgTestCases[] = {
277 278 279 280 281 282 283 284
        { "No Failure",                         MockLinkMissionItemHandler::FailNone },
        { "FailReadRequestListNoResponse",      MockLinkMissionItemHandler::FailReadRequestListNoResponse },
        { "FailReadRequest0NoResponse",         MockLinkMissionItemHandler::FailReadRequest0NoResponse },
        { "FailReadRequest1NoResponse",         MockLinkMissionItemHandler::FailReadRequest1NoResponse },
        { "FailReadRequest0IncorrectSequence",  MockLinkMissionItemHandler::FailReadRequest0IncorrectSequence },
        { "FailReadRequest1IncorrectSequence",  MockLinkMissionItemHandler::FailReadRequest1IncorrectSequence  },
        { "FailReadRequest0ErrorAck",           MockLinkMissionItemHandler::FailReadRequest0ErrorAck },
        { "FailReadRequest1ErrorAck",           MockLinkMissionItemHandler::FailReadRequest1ErrorAck },
285 286 287
    };
    
    for (size_t i=0; i<sizeof(rgTestCases)/sizeof(rgTestCases[0]); i++) {
288 289
        qDebug() << "TEST CASE " << rgTestCases[i].failureText;
        _roundTripItems(rgTestCases[i].failureMode);
290
        _mockLink->resetMissionItemHandler();
291
        _multiSpyMissionManager->clearAllSignals();
292 293
    }
}
Don Gagne's avatar
Don Gagne committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

void MissionManagerTest::_testWriteFailureHandlingAPM(void)
{
    _initForFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA);
    _testWriteFailureHandlingWorker();
}

void MissionManagerTest::_testReadFailureHandlingAPM(void)
{
    _initForFirmwareType(MAV_AUTOPILOT_ARDUPILOTMEGA);
    _testReadFailureHandlingWorker();
}


void MissionManagerTest::_testWriteFailureHandlingPX4(void)
{
    _initForFirmwareType(MAV_AUTOPILOT_PX4);
    _testWriteFailureHandlingWorker();
}

void MissionManagerTest::_testReadFailureHandlingPX4(void)
{
    _initForFirmwareType(MAV_AUTOPILOT_PX4);
    _testReadFailureHandlingWorker();
}