• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mavlink / MAVSDK / 12401616260

18 Dec 2024 09:26PM UTC coverage: 44.627% (+1.0%) from 43.59%
12401616260

push

github

web-flow
Support Mission Download In Mission Raw Server (#2463)

* Add mission download support (air to ground) in mission raw server

* Removed unused private variable

* Point proto back to mavlink root

---------

Co-authored-by: Jon Reeves <jon.reeves@elroyair.com>

667 of 723 new or added lines in 3 files covered. (92.25%)

3 existing lines in 3 files now uncovered.

14584 of 32680 relevant lines covered (44.63%)

284.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.17
/src/mavsdk/core/mavlink_mission_transfer_server_test.cpp
1
#include <algorithm>
2
#include <chrono>
3
#include <future>
4
#include <gtest/gtest.h>
5

6
#include "mavlink_mission_transfer_server.h"
7
#include "mocks/sender_mock.h"
8
#include "unused.h"
9

10
using namespace mavsdk;
11

12
using ::testing::_;
13
using ::testing::NiceMock;
14
using ::testing::Return;
15
using ::testing::Truly;
16
using MockSender = NiceMock<mavsdk::testing::MockSender>;
17

18
using Result = MavlinkMissionTransferServer::Result;
19
using ItemInt = MavlinkMissionTransferServer::ItemInt;
20

21
static MavlinkAddress own_address{42, 16};
22
static uint8_t channel{0};
23
static MavlinkAddress target_address{99, MAV_COMP_ID_AUTOPILOT1};
24

25
static constexpr double timeout_s = 0.5;
26

27
#define ONCE_ONLY \
28
    static bool called = false; \
29
    EXPECT_FALSE(called); \
30
    called = true
31

32
class MavlinkMissionTransferServerTest : public ::testing::Test {
33
protected:
34
    MavlinkMissionTransferServerTest() :
35✔
35
        ::testing::Test(),
36
        timeout_handler(time),
35✔
37
        mmt(mock_sender, message_handler, timeout_handler, []() { return timeout_s; })
106✔
38
    {}
35✔
39

40
    void SetUp() override
35✔
41
    {
42
        ON_CALL(mock_sender, get_own_system_id()).WillByDefault(Return(own_address.system_id));
35✔
43
        ON_CALL(mock_sender, get_own_component_id())
105✔
44
            .WillByDefault(Return(own_address.component_id));
105✔
45
        ON_CALL(mock_sender, autopilot()).WillByDefault(Return(Autopilot::Px4));
35✔
46
    }
35✔
47

48
    static ItemInt make_item(uint8_t type, uint16_t sequence)
67✔
49
    {
50
        ItemInt item;
51

52
        item.seq = sequence;
67✔
53
        item.frame = MAV_FRAME_MISSION;
67✔
54
        item.command = MAV_CMD_NAV_WAYPOINT;
67✔
55
        item.current = uint8_t(sequence == 0 ? 1 : 0);
67✔
56
        item.autocontinue = 1;
67✔
57
        item.param1 = 1.0f;
67✔
58
        item.param2 = 2.0f;
67✔
59
        item.param3 = 3.0f;
67✔
60
        item.param4 = 4.0f;
67✔
61
        item.x = 5;
67✔
62
        item.y = 6;
67✔
63
        item.z = 7.0f;
67✔
64
        item.mission_type = type;
67✔
65

66
        return item;
67✔
67
    }
68

69
    static mavlink_message_t make_mission_count(unsigned count)
1✔
70
    {
71
        mavlink_message_t message;
72
        mavlink_msg_mission_count_pack(
1✔
73
            own_address.system_id,
1✔
74
            own_address.component_id,
1✔
75
            &message,
76
            target_address.system_id,
1✔
77
            target_address.component_id,
1✔
78
            count,
79
            MAV_MISSION_TYPE_MISSION,
80
            0);
81
        return message;
1✔
82
    }
83

84
    static bool is_correct_autopilot_mission_request_int(
15✔
85
        uint8_t type, unsigned sequence, uint8_t target_component, const mavlink_message_t& message)
86
    {
87
        if (message.msgid != MAVLINK_MSG_ID_MISSION_REQUEST_INT) {
15✔
NEW
88
            return false;
×
89
        }
90

91
        mavlink_mission_request_int_t mission_request_int;
15✔
92
        mavlink_msg_mission_request_int_decode(&message, &mission_request_int);
15✔
93
        return (
94
            message.sysid == own_address.system_id && message.compid == own_address.component_id &&
15✔
95
            mission_request_int.target_system == target_address.system_id &&
15✔
96
            mission_request_int.target_component == target_component &&
15✔
97
            mission_request_int.seq == sequence && mission_request_int.mission_type == type);
30✔
98
    }
99

100
    static bool is_correct_autopilot_mission_ack(
2✔
101
        uint8_t type, uint8_t result, uint8_t target_component, const mavlink_message_t& message)
102
    {
103
        if (message.msgid != MAVLINK_MSG_ID_MISSION_ACK) {
2✔
NEW
104
            return false;
×
105
        }
106

107
        mavlink_mission_ack_t ack;
2✔
108
        mavlink_msg_mission_ack_decode(&message, &ack);
2✔
109
        return (
110
            message.sysid == own_address.system_id && message.compid == own_address.component_id &&
2✔
111
            ack.target_system == target_address.system_id &&
2✔
112
            ack.target_component == target_component && ack.type == result &&
6✔
113
            ack.mission_type == type);
4✔
114
    }
115

116
    static bool is_the_same_mission_item_int(const ItemInt& item, const mavlink_message_t& message)
31✔
117
    {
118
        if (message.msgid != MAVLINK_MSG_ID_MISSION_ITEM_INT) {
31✔
NEW
119
            return false;
×
120
        }
121
        mavlink_mission_item_int_t mission_item_int;
31✔
122
        mavlink_msg_mission_item_int_decode(&message, &mission_item_int);
31✔
123

124
        return (
125
            message.sysid == own_address.system_id && //
62✔
126
            message.compid == own_address.component_id && //
31✔
127
            mission_item_int.target_system == target_address.system_id && //
31✔
128
            mission_item_int.target_component == target_address.component_id && //
31✔
129
            mission_item_int.seq == item.seq && //
31✔
130
            mission_item_int.frame == item.frame && //
31✔
131
            mission_item_int.command == item.command && //
31✔
132
            mission_item_int.current == item.current && //
31✔
133
            mission_item_int.autocontinue == item.autocontinue && //
31✔
134
            mission_item_int.param1 == item.param1 && //
31✔
135
            mission_item_int.param2 == item.param2 && //
31✔
136
            mission_item_int.param3 == item.param3 && //
31✔
137
            mission_item_int.param4 == item.param4 && //
31✔
138
            mission_item_int.x == item.x && //
31✔
139
            mission_item_int.y == item.y && //
31✔
140
            mission_item_int.z == item.z && //
93✔
141
            mission_item_int.mission_type == item.mission_type);
62✔
142
    }
143

144
    static mavlink_message_t
145
    make_mission_item(const std::vector<ItemInt>& item_ints, std::size_t index)
2✔
146
    {
147
        mavlink_message_t message;
148
        mavlink_msg_mission_item_int_pack(
10✔
149
            own_address.system_id,
2✔
150
            own_address.component_id,
2✔
151
            &message,
152
            target_address.system_id,
2✔
153
            target_address.component_id,
2✔
154
            index,
155
            item_ints[index].frame,
2✔
156
            item_ints[index].command,
2✔
157
            item_ints[index].current,
2✔
158
            item_ints[index].autocontinue,
2✔
159
            item_ints[index].param1,
2✔
160
            item_ints[index].param2,
2✔
161
            item_ints[index].param3,
2✔
162
            item_ints[index].param4,
2✔
163
            item_ints[index].x,
2✔
164
            item_ints[index].y,
2✔
165
            item_ints[index].z,
2✔
166
            item_ints[index].mission_type);
2✔
167
        return message;
2✔
168
    }
169

170
    static bool
171
    is_correct_mission_send_count(uint8_t type, unsigned count, const mavlink_message_t& message)
8✔
172
    {
173
        if (message.msgid != MAVLINK_MSG_ID_MISSION_COUNT) {
8✔
NEW
174
            return false;
×
175
        }
176

177
        mavlink_mission_count_t mission_count;
8✔
178
        mavlink_msg_mission_count_decode(&message, &mission_count);
8✔
179

180
        return (
181
            message.msgid == MAVLINK_MSG_ID_MISSION_COUNT &&
16✔
182
            message.sysid == own_address.system_id && message.compid == own_address.component_id &&
8✔
183
            mission_count.target_system == target_address.system_id &&
8✔
184
            mission_count.target_component == target_address.component_id &&
8✔
185
            mission_count.count == count && mission_count.mission_type == type);
16✔
186
    }
187

188
    static mavlink_message_t make_mission_request_int(uint8_t type, int sequence)
34✔
189
    {
190
        mavlink_message_t message;
191
        mavlink_msg_mission_request_int_pack(
34✔
192
            own_address.system_id,
34✔
193
            own_address.component_id,
34✔
194
            &message,
195
            target_address.system_id,
34✔
196
            target_address.component_id,
34✔
197
            sequence,
198
            type);
199
        return message;
34✔
200
    }
201

202
    static mavlink_message_t make_mission_ack(uint8_t type, uint8_t result)
23✔
203
    {
204
        mavlink_message_t message;
205
        mavlink_msg_mission_ack_pack(
23✔
206
            own_address.system_id,
23✔
207
            own_address.component_id,
23✔
208
            &message,
209
            target_address.system_id,
23✔
210
            target_address.component_id,
23✔
211
            result,
212
            type,
213
            0);
214
        return message;
23✔
215
    }
216

217
    static mavlink_message_t make_mission_request(uint8_t type, int sequence)
1✔
218
    {
219
        mavlink_message_t message;
220
        mavlink_msg_mission_request_pack(
1✔
221
            target_address.system_id,
1✔
222
            target_address.component_id,
1✔
223
            &message,
224
            own_address.system_id,
1✔
225
            own_address.component_id,
1✔
226
            sequence,
227
            type);
228
        return message;
1✔
229
    }
230

231
    static bool
232
    is_correct_mission_ack(uint8_t type, uint8_t result, const mavlink_message_t& message)
2✔
233
    {
234
        if (message.msgid != MAVLINK_MSG_ID_MISSION_ACK) {
2✔
NEW
235
            return false;
×
236
        }
237

238
        mavlink_mission_ack_t ack;
2✔
239
        mavlink_msg_mission_ack_decode(&message, &ack);
2✔
240
        return (
241
            message.sysid == own_address.system_id && message.compid == own_address.component_id &&
2✔
242
            ack.target_system == target_address.system_id &&
2✔
243
            ack.target_component == target_address.component_id && ack.type == result &&
6✔
244
            ack.mission_type == type);
4✔
245
    }
246

247
    MockSender mock_sender;
248
    MavlinkMessageHandler message_handler;
249
    FakeTime time;
250
    TimeoutHandler timeout_handler;
251
    MavlinkMissionTransferServer mmt;
252
};
253

254
TEST_F(MavlinkMissionTransferServerTest, ReceiveIncomingMissionSendsMissionRequests)
4✔
255
{
256
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
257

258
    std::vector<ItemInt> items;
1✔
259
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
260
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
261

262
    mmt.receive_incoming_items_async(
2✔
263
        MAV_MISSION_TYPE_MISSION,
264
        items.size(),
1✔
265
        target_address.system_id,
1✔
266
        target_address.component_id,
1✔
267
        [](Result result, const std::vector<ItemInt>& output_items) {
×
268
            UNUSED(output_items);
×
269
            UNUSED(result);
×
270
            EXPECT_TRUE(false);
×
271
        });
×
272

273
    EXPECT_CALL(
2✔
274
        mock_sender,
275
        queue_message(Truly([](std::function<mavlink_message_t(
276
                                   MavlinkAddress mavlink_address, uint8_t channel)> fun) {
277
            return is_correct_autopilot_mission_request_int(
278
                MAV_MISSION_TYPE_MISSION,
279
                0,
280
                target_address.component_id,
281
                fun(own_address, channel));
282
        })));
283

284
    mmt.do_work();
1✔
285

286
    message_handler.process_message(make_mission_count(items.size()));
1✔
287
}
1✔
288

289
TEST_F(
4✔
290
    MavlinkMissionTransferServerTest,
291
    ReceiveIncomingMissionResendsMissionRequestsAndTimesOutEventually)
292
{
293
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
294

295
    std::vector<ItemInt> items;
1✔
296
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
297
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
298

299
    std::promise<void> prom;
1✔
300
    auto fut = prom.get_future();
1✔
301
    mmt.receive_incoming_items_async(
2✔
302
        MAV_MISSION_TYPE_MISSION,
303
        items.size(),
1✔
304
        target_address.system_id,
1✔
305
        target_address.component_id,
1✔
306
        [&prom](Result result, const std::vector<ItemInt>& output_items) {
2✔
307
            UNUSED(output_items);
1✔
308
            EXPECT_EQ(result, Result::Timeout);
1✔
309
            prom.set_value();
1✔
310
        });
1✔
311

312
    EXPECT_CALL(
8✔
313
        mock_sender,
314
        queue_message(Truly([](std::function<mavlink_message_t(
315
                                   MavlinkAddress mavlink_address, uint8_t channel)> fun) {
316
            return is_correct_autopilot_mission_request_int(
317
                MAV_MISSION_TYPE_MISSION,
318
                0,
319
                target_address.component_id,
320
                fun(own_address, channel));
321
        })))
322
        .Times(MavlinkMissionTransferServer::retries);
3✔
323

324
    mmt.do_work();
1✔
325

326
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(0)), std::future_status::timeout);
1✔
327

328
    // After the specified retries we should give up with a timeout.
329
    for (unsigned i = 0; i < MavlinkMissionTransferServer::retries; ++i) {
6✔
330
        time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
5✔
331
        timeout_handler.run_once();
5✔
332
    }
333

334
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
335

336
    mmt.do_work();
1✔
337
    EXPECT_TRUE(mmt.is_idle());
1✔
338
}
1✔
339

340
TEST_F(MavlinkMissionTransferServerTest, ReceiveIncomingMissionResendsRequestItemAgainForSecondItem)
4✔
341
{
342
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
343

344
    std::vector<ItemInt> items;
1✔
345
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
346
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
347
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 2));
1✔
348

349
    std::promise<void> prom;
1✔
350
    auto fut = prom.get_future();
1✔
351
    mmt.receive_incoming_items_async(
2✔
352
        MAV_MISSION_TYPE_MISSION,
353
        items.size(),
1✔
354
        target_address.system_id,
1✔
355
        target_address.component_id,
1✔
356
        [&prom](Result result, const std::vector<ItemInt>& output_items) {
2✔
357
            UNUSED(output_items);
1✔
358
            EXPECT_EQ(result, Result::Timeout);
1✔
359
            prom.set_value();
1✔
360
        });
1✔
361

362
    // We almost exhaust the retries of the first one.
363
    EXPECT_CALL(
7✔
364
        mock_sender,
365
        queue_message(Truly([](std::function<mavlink_message_t(
366
                                   MavlinkAddress mavlink_address, uint8_t channel)> fun) {
367
            return is_correct_autopilot_mission_request_int(
368
                MAV_MISSION_TYPE_MISSION,
369
                0,
370
                target_address.component_id,
371
                fun(own_address, channel));
372
        })))
373
        .Times(MavlinkMissionTransferServer::retries - 1);
3✔
374

375
    mmt.do_work();
1✔
376

377
    for (unsigned i = 0; i < MavlinkMissionTransferServer::retries - 2; ++i) {
4✔
378
        time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
3✔
379
        timeout_handler.run_once();
3✔
380
    }
381

382
    // This time we go over the retry limit.
383
    EXPECT_CALL(
8✔
384
        mock_sender,
385
        queue_message(Truly([](std::function<mavlink_message_t(
386
                                   MavlinkAddress mavlink_address, uint8_t channel)> fun) {
387
            return is_correct_autopilot_mission_request_int(
388
                MAV_MISSION_TYPE_MISSION,
389
                1,
390
                target_address.component_id,
391
                fun(own_address, channel));
392
        })))
393
        .Times(MavlinkMissionTransferServer::retries);
3✔
394

395
    message_handler.process_message(make_mission_item(items, 0));
1✔
396

397
    for (unsigned i = 0; i < MavlinkMissionTransferServer::retries; ++i) {
6✔
398
        time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
5✔
399
        timeout_handler.run_once();
5✔
400
    }
401

402
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
403

404
    mmt.do_work();
1✔
405
    EXPECT_TRUE(mmt.is_idle());
1✔
406
}
1✔
407

408
TEST_F(MavlinkMissionTransferServerTest, ReceiveIncomingMissionEmptyList)
4✔
409
{
410
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
411

412
    std::promise<void> prom;
1✔
413
    auto fut = prom.get_future();
1✔
414
    mmt.receive_incoming_items_async(
2✔
415
        MAV_MISSION_TYPE_MISSION,
416
        0,
417
        target_address.system_id,
1✔
418
        target_address.component_id,
1✔
419
        [&prom](Result result, const std::vector<ItemInt>& items) {
2✔
420
            UNUSED(items);
1✔
421
            EXPECT_EQ(result, Result::Success);
1✔
422
            prom.set_value();
1✔
423
        });
1✔
424

425
    EXPECT_CALL(
2✔
426
        mock_sender,
427
        queue_message(Truly([](std::function<mavlink_message_t(
428
                                   MavlinkAddress mavlink_address, uint8_t channel)> fun) {
429
            return is_correct_autopilot_mission_ack(
430
                MAV_MISSION_TYPE_MISSION,
431
                MAV_MISSION_ACCEPTED,
432
                target_address.component_id,
433
                fun(own_address, channel));
434
        })));
435

436
    mmt.do_work();
1✔
437

438
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
439

440
    // We want to be sure a timeout is not still triggered later.
441
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
1✔
442
    timeout_handler.run_once();
1✔
443

444
    mmt.do_work();
1✔
445
    EXPECT_TRUE(mmt.is_idle());
1✔
446
}
1✔
447

448
TEST_F(MavlinkMissionTransferServerTest, ReceiveIncomingMissionCanBeCancelled)
4✔
449
{
450
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
451

452
    std::vector<ItemInt> items;
1✔
453
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
454
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
455
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 2));
1✔
456

457
    std::promise<void> prom;
1✔
458
    auto fut = prom.get_future();
1✔
459
    auto transfer = mmt.receive_incoming_items_async(
1✔
460
        MAV_MISSION_TYPE_MISSION,
461
        items.size(),
1✔
462
        target_address.system_id,
1✔
463
        target_address.component_id,
1✔
464
        [&prom](Result result, const std::vector<ItemInt>& output_items) {
2✔
465
            UNUSED(output_items);
1✔
466
            EXPECT_EQ(result, Result::Cancelled);
1✔
467
            prom.set_value();
1✔
468
        });
3✔
469
    mmt.do_work();
1✔
470

471
    message_handler.process_message(make_mission_item(items, 0));
1✔
472

473
    EXPECT_CALL(
2✔
474
        mock_sender,
475
        queue_message(Truly([](std::function<mavlink_message_t(
476
                                   MavlinkAddress mavlink_address, uint8_t channel)> fun) {
477
            return is_correct_autopilot_mission_ack(
478
                MAV_MISSION_TYPE_MISSION,
479
                MAV_MISSION_OPERATION_CANCELLED,
480
                target_address.component_id,
481
                fun(own_address, channel));
482
        })));
483

484
    auto ptr = transfer.lock();
1✔
485
    EXPECT_TRUE(ptr);
1✔
486
    if (ptr) {
1✔
487
        ptr->cancel();
1✔
488
    }
489

490
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
491

492
    mmt.do_work();
1✔
493
    EXPECT_TRUE(mmt.is_idle());
1✔
494
}
1✔
495

496
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionEmptyMission)
4✔
497
{
498
    std::vector<ItemInt> items;
1✔
499

500
    std::promise<void> prom;
1✔
501
    auto fut = prom.get_future();
1✔
502

503
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
504

505
    mmt.send_outgoing_items_async(
2✔
506
        MAV_MISSION_TYPE_MISSION,
507
        items,
508
        target_address.system_id,
1✔
509
        target_address.component_id,
1✔
510
        [&prom](Result result) {
2✔
511
            EXPECT_EQ(result, Result::Success);
1✔
512
            ONCE_ONLY;
1✔
513
            prom.set_value();
1✔
514
        });
1✔
515
    mmt.do_work();
1✔
516

517
    // empty mission should just send a zero count and be done
518
    message_handler.process_message(
2✔
519
        make_mission_ack(MAV_MISSION_TYPE_MISSION, MAV_MISSION_ACCEPTED));
2✔
520

521
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
522

523
    mmt.do_work();
1✔
524
    EXPECT_TRUE(mmt.is_idle());
1✔
525
}
1✔
526

527
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionDoesNotCrashIfCallbackIsNull)
4✔
528
{
529
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(false));
1✔
530

531
    // Catch the empty case
532
    std::vector<ItemInt> items;
1✔
533
    mmt.send_outgoing_items_async(
2✔
534
        MAV_MISSION_TYPE_MISSION,
535
        items,
536
        target_address.system_id,
1✔
537
        target_address.component_id,
1✔
538
        nullptr);
539
    mmt.do_work();
1✔
540

541
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
542
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
543

544
    mmt.send_outgoing_items_async(
2✔
545
        MAV_MISSION_TYPE_MISSION,
546
        items,
547
        target_address.system_id,
1✔
548
        target_address.component_id,
1✔
549
        nullptr);
550
    mmt.do_work();
1✔
551

552
    // Catch the WrongSequence case as well.
553
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 3));
1✔
554
    mmt.send_outgoing_items_async(
2✔
555
        MAV_MISSION_TYPE_MISSION,
556
        items,
557
        target_address.system_id,
1✔
558
        target_address.component_id,
1✔
559
        nullptr);
560
    mmt.do_work();
1✔
561

562
    mmt.do_work();
1✔
563
    EXPECT_TRUE(mmt.is_idle());
1✔
564
}
1✔
565

566
TEST_F(
4✔
567
    MavlinkMissionTransferServerTest, SendOutgoingMissionReturnsConnectionErrorWhenSendMessageFails)
568
{
569
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(false));
1✔
570

571
    std::vector<ItemInt> items;
1✔
572
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
573
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
574

575
    std::promise<void> prom;
1✔
576
    auto fut = prom.get_future();
1✔
577

578
    mmt.send_outgoing_items_async(
2✔
579
        MAV_MISSION_TYPE_MISSION,
580
        items,
581
        target_address.system_id,
1✔
582
        target_address.component_id,
1✔
583
        [&prom](Result result) {
2✔
584
            EXPECT_EQ(result, Result::ConnectionError);
1✔
585
            ONCE_ONLY;
1✔
586
            prom.set_value();
1✔
587
        });
1✔
588
    mmt.do_work();
1✔
589

590
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
591

592
    // We want to be sure a timeout is not still triggered later.
593
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
1✔
594
    timeout_handler.run_once();
1✔
595

596
    mmt.do_work();
1✔
597
    EXPECT_TRUE(mmt.is_idle());
1✔
598
}
1✔
599

600
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionSendsCount)
4✔
601
{
602
    std::vector<ItemInt> items;
1✔
603
    items.push_back(make_item(MAV_MISSION_TYPE_FENCE, 0));
1✔
604
    items.push_back(make_item(MAV_MISSION_TYPE_FENCE, 1));
1✔
605

606
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
607

608
    EXPECT_CALL(
2✔
609
        mock_sender,
610
        queue_message(Truly([&items](std::function<mavlink_message_t(
611
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
612
            return is_correct_mission_send_count(
613
                MAV_MISSION_TYPE_FENCE, items.size(), fun(own_address, channel));
614
        })));
615

616
    mmt.send_outgoing_items_async(
2✔
617
        MAV_MISSION_TYPE_FENCE,
618
        items,
619
        target_address.system_id,
1✔
620
        target_address.component_id,
1✔
NEW
621
        [](Result result) {
×
NEW
622
            UNUSED(result);
×
NEW
623
            EXPECT_TRUE(false);
×
NEW
624
        });
×
625
    mmt.do_work();
1✔
626
}
1✔
627

628
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionResendsCount)
4✔
629
{
630
    std::vector<ItemInt> items;
1✔
631
    items.push_back(make_item(MAV_MISSION_TYPE_FENCE, 0));
1✔
632
    items.push_back(make_item(MAV_MISSION_TYPE_FENCE, 1));
1✔
633

634
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
635

636
    EXPECT_CALL(
5✔
637
        mock_sender,
638
        queue_message(Truly([&items](std::function<mavlink_message_t(
639
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
640
            return is_correct_mission_send_count(
641
                MAV_MISSION_TYPE_FENCE, items.size(), fun(own_address, channel));
642
        })))
643
        .Times(2);
3✔
644

645
    mmt.send_outgoing_items_async(
2✔
646
        MAV_MISSION_TYPE_FENCE,
647
        items,
648
        target_address.system_id,
1✔
649
        target_address.component_id,
1✔
NEW
650
        [](Result result) {
×
NEW
651
            UNUSED(result);
×
NEW
652
            EXPECT_TRUE(false);
×
NEW
653
        });
×
654
    mmt.do_work();
1✔
655

656
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
1✔
657
    timeout_handler.run_once();
1✔
658
}
1✔
659

660
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionTimeoutAfterSendCount)
4✔
661
{
662
    std::vector<ItemInt> items;
1✔
663
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
664
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
665

666
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
667

668
    EXPECT_CALL(
8✔
669
        mock_sender,
670
        queue_message(Truly([&items](std::function<mavlink_message_t(
671
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
672
            return is_correct_mission_send_count(
673
                MAV_MISSION_TYPE_MISSION, items.size(), fun(own_address, channel));
674
        })))
675
        .Times(MavlinkMissionTransferServer::retries);
3✔
676

677
    std::promise<void> prom;
1✔
678
    auto fut = prom.get_future();
1✔
679

680
    mmt.send_outgoing_items_async(
2✔
681
        MAV_MISSION_TYPE_MISSION,
682
        items,
683
        target_address.system_id,
1✔
684
        target_address.component_id,
1✔
685
        [&prom](Result result) {
2✔
686
            EXPECT_EQ(result, Result::Timeout);
1✔
687
            ONCE_ONLY;
1✔
688
            prom.set_value();
1✔
689
        });
1✔
690
    mmt.do_work();
1✔
691

692
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(0)), std::future_status::timeout);
1✔
693

694
    // After the specified retries we should give up with a timeout.
695
    for (unsigned i = 0; i < MavlinkMissionTransferServer::retries; ++i) {
6✔
696
        time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
5✔
697
        timeout_handler.run_once();
5✔
698
    }
699

700
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
701
}
1✔
702

703
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionSendsMissionItems)
4✔
704
{
705
    std::vector<ItemInt> items;
1✔
706
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
707
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
708

709
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
710

711
    std::promise<void> prom;
1✔
712
    auto fut = prom.get_future();
1✔
713

714
    mmt.send_outgoing_items_async(
2✔
715
        MAV_MISSION_TYPE_MISSION,
716
        items,
717
        target_address.system_id,
1✔
718
        target_address.component_id,
1✔
719
        [&prom](Result result) {
2✔
720
            EXPECT_EQ(result, Result::Success);
1✔
721
            ONCE_ONLY;
1✔
722
            prom.set_value();
1✔
723
        });
1✔
724
    mmt.do_work();
1✔
725

726
    EXPECT_CALL(
2✔
727
        mock_sender,
728
        queue_message(Truly([&items](std::function<mavlink_message_t(
729
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
730
            return is_the_same_mission_item_int(items[0], fun(own_address, channel));
731
        })));
732

733
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
1✔
734

735
    EXPECT_CALL(
2✔
736
        mock_sender,
737
        queue_message(Truly([&items](std::function<mavlink_message_t(
738
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
739
            return is_the_same_mission_item_int(items[1], fun(own_address, channel));
740
        })));
741

742
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 1));
1✔
743

744
    message_handler.process_message(
2✔
745
        make_mission_ack(MAV_MISSION_TYPE_MISSION, MAV_MISSION_ACCEPTED));
2✔
746

747
    // We are finished and should have received the successful result.
748
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
749

750
    // We do not expect a timeout later though.
751
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
1✔
752
    timeout_handler.run_once();
1✔
753

754
    mmt.do_work();
1✔
755
    EXPECT_TRUE(mmt.is_idle());
1✔
756
}
1✔
757

758
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionResendsMissionItems)
4✔
759
{
760
    std::vector<ItemInt> items;
1✔
761
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
762
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
763

764
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
765

766
    std::promise<void> prom;
1✔
767
    auto fut = prom.get_future();
1✔
768

769
    mmt.send_outgoing_items_async(
2✔
770
        MAV_MISSION_TYPE_MISSION,
771
        items,
772
        target_address.system_id,
1✔
773
        target_address.component_id,
1✔
774
        [&prom](Result result) {
2✔
775
            EXPECT_EQ(result, Result::Success);
1✔
776
            ONCE_ONLY;
1✔
777
            prom.set_value();
1✔
778
        });
1✔
779
    mmt.do_work();
1✔
780

781
    EXPECT_CALL(
2✔
782
        mock_sender,
783
        queue_message(Truly([&items](std::function<mavlink_message_t(
784
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
785
            return is_the_same_mission_item_int(items[0], fun(own_address, channel));
786
        })));
787

788
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
1✔
789

790
    EXPECT_CALL(
2✔
791
        mock_sender,
792
        queue_message(Truly([&items](std::function<mavlink_message_t(
793
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
794
            return is_the_same_mission_item_int(items[0], fun(own_address, channel));
795
        })));
796

797
    // Request 0 again in case it had not arrived.
798
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
1✔
799

800
    EXPECT_CALL(
2✔
801
        mock_sender,
802
        queue_message(Truly([&items](std::function<mavlink_message_t(
803
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
804
            return is_the_same_mission_item_int(items[1], fun(own_address, channel));
805
        })));
806

807
    // Request 1 finally.
808
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 1));
1✔
809

810
    message_handler.process_message(
2✔
811
        make_mission_ack(MAV_MISSION_TYPE_MISSION, MAV_MISSION_ACCEPTED));
2✔
812

813
    // We are finished and should have received the successful result.
814
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
815

816
    mmt.do_work();
1✔
817
    EXPECT_TRUE(mmt.is_idle());
1✔
818
}
1✔
819

820
TEST_F(
4✔
821
    MavlinkMissionTransferServerTest,
822
    SendOutgoingMissionResendsMissionItemsButGivesUpAfterSomeRetries)
823
{
824
    std::vector<ItemInt> items;
1✔
825
    items.push_back(make_item(MAV_MISSION_TYPE_FENCE, 0));
1✔
826
    items.push_back(make_item(MAV_MISSION_TYPE_FENCE, 1));
1✔
827

828
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
829

830
    std::promise<void> prom;
1✔
831
    auto fut = prom.get_future();
1✔
832

833
    mmt.send_outgoing_items_async(
2✔
834
        MAV_MISSION_TYPE_FENCE,
835
        items,
836
        target_address.system_id,
1✔
837
        target_address.component_id,
1✔
838
        [&prom](Result result) {
2✔
839
            EXPECT_EQ(result, Result::Timeout);
1✔
840
            ONCE_ONLY;
1✔
841
            prom.set_value();
1✔
842
        });
1✔
843
    mmt.do_work();
1✔
844

845
    EXPECT_CALL(
8✔
846
        mock_sender,
847
        queue_message(Truly([&items](std::function<mavlink_message_t(
848
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
849
            return is_the_same_mission_item_int(items[0], fun(own_address, channel));
850
        })))
851
        .Times(MavlinkMissionTransferServer::retries);
3✔
852

853
    for (unsigned i = 0; i < MavlinkMissionTransferServer::retries; ++i) {
6✔
854
        message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
5✔
855
    }
856

857
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(0)), std::future_status::timeout);
1✔
858

859
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
1✔
860

861
    // We are finished and should have received the successful result.
862
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
863

864
    mmt.do_work();
1✔
865
    EXPECT_TRUE(mmt.is_idle());
1✔
866
}
1✔
867

868
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionAckArrivesTooEarly)
4✔
869
{
870
    std::vector<ItemInt> items;
1✔
871
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
872
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
873

874
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
875

876
    std::promise<void> prom;
1✔
877
    auto fut = prom.get_future();
1✔
878

879
    mmt.send_outgoing_items_async(
2✔
880
        MAV_MISSION_TYPE_MISSION,
881
        items,
882
        target_address.system_id,
1✔
883
        target_address.component_id,
1✔
884
        [&prom](Result result) {
2✔
885
            EXPECT_EQ(result, Result::ProtocolError);
1✔
886
            ONCE_ONLY;
1✔
887
            prom.set_value();
1✔
888
        });
1✔
889
    mmt.do_work();
1✔
890

891
    EXPECT_CALL(
2✔
892
        mock_sender,
893
        queue_message(Truly([&items](std::function<mavlink_message_t(
894
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
895
            return is_the_same_mission_item_int(items[0], fun(own_address, channel));
896
        })));
897

898
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
1✔
899

900
    // Don't request item 1 but already send ack.
901
    message_handler.process_message(
2✔
902
        make_mission_ack(MAV_MISSION_TYPE_MISSION, MAV_MISSION_ACCEPTED));
2✔
903

904
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
905

906
    mmt.do_work();
1✔
907
    EXPECT_TRUE(mmt.is_idle());
1✔
908
}
1✔
909

910
class MavlinkMissionTransferServerNackTests
911
    : public MavlinkMissionTransferServerTest,
912
      public ::testing::WithParamInterface<std::pair<uint8_t, Result>> {};
913

914
TEST_P(MavlinkMissionTransferServerNackTests, SendOutgoingMissionNackAreHandled)
31✔
915
{
916
    uint8_t mavlink_nack = std::get<0>(GetParam());
15✔
917
    Result mavsdk_nack = std::get<1>(GetParam());
15✔
918

919
    std::vector<ItemInt> items;
15✔
920
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
15✔
921
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
15✔
922

923
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
15✔
924

925
    std::promise<void> prom;
15✔
926
    auto fut = prom.get_future();
15✔
927

928
    mmt.send_outgoing_items_async(
30✔
929
        MAV_MISSION_TYPE_MISSION,
930
        items,
931
        target_address.system_id,
15✔
932
        target_address.component_id,
15✔
933
        [&prom, &mavsdk_nack](Result result) {
45✔
934
            EXPECT_EQ(result, mavsdk_nack);
15✔
935
            prom.set_value();
15✔
936
        });
15✔
937
    mmt.do_work();
15✔
938

939
    EXPECT_CALL(
30✔
940
        mock_sender,
941
        queue_message(Truly([&items](std::function<mavlink_message_t(
942
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
943
            return is_the_same_mission_item_int(items[0], fun(own_address, channel));
944
        })));
945

946
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
15✔
947

948
    // Send nack now.
949
    message_handler.process_message(make_mission_ack(MAV_MISSION_TYPE_MISSION, mavlink_nack));
15✔
950

951
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
15✔
952

953
    mmt.do_work();
15✔
954
    EXPECT_TRUE(mmt.is_idle());
15✔
955
}
15✔
956

957
INSTANTIATE_TEST_SUITE_P(
16✔
958
    MavlinkMissionTransferServerTests,
959
    MavlinkMissionTransferServerNackTests,
960
    ::testing::Values(
961
        std::make_pair(MAV_MISSION_ERROR, Result::ProtocolError),
962
        std::make_pair(MAV_MISSION_UNSUPPORTED_FRAME, Result::UnsupportedFrame),
963
        std::make_pair(MAV_MISSION_UNSUPPORTED, Result::Unsupported),
964
        std::make_pair(MAV_MISSION_NO_SPACE, Result::TooManyMissionItems),
965
        std::make_pair(MAV_MISSION_INVALID, Result::InvalidParam),
966
        std::make_pair(MAV_MISSION_INVALID_PARAM1, Result::InvalidParam),
967
        std::make_pair(MAV_MISSION_INVALID_PARAM2, Result::InvalidParam),
968
        std::make_pair(MAV_MISSION_INVALID_PARAM3, Result::InvalidParam),
969
        std::make_pair(MAV_MISSION_INVALID_PARAM4, Result::InvalidParam),
970
        std::make_pair(MAV_MISSION_INVALID_PARAM5_X, Result::InvalidParam),
971
        std::make_pair(MAV_MISSION_INVALID_PARAM6_Y, Result::InvalidParam),
972
        std::make_pair(MAV_MISSION_INVALID_PARAM7, Result::InvalidParam),
973
        std::make_pair(MAV_MISSION_INVALID_SEQUENCE, Result::InvalidSequence),
974
        std::make_pair(MAV_MISSION_DENIED, Result::Denied),
975
        std::make_pair(MAV_MISSION_OPERATION_CANCELLED, Result::Cancelled)));
976

977
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionTimeoutNotTriggeredDuringTransfer)
4✔
978
{
979
    std::vector<ItemInt> items;
1✔
980
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
981
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
982
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 2));
1✔
983

984
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
985

986
    std::promise<void> prom;
1✔
987
    auto fut = prom.get_future();
1✔
988

989
    mmt.send_outgoing_items_async(
2✔
990
        MAV_MISSION_TYPE_MISSION,
991
        items,
992
        target_address.system_id,
1✔
993
        target_address.component_id,
1✔
994
        [&prom](Result result) {
2✔
995
            EXPECT_EQ(result, Result::Success);
1✔
996
            ONCE_ONLY;
1✔
997
            prom.set_value();
1✔
998
        });
1✔
999
    mmt.do_work();
1✔
1000

1001
    EXPECT_CALL(
2✔
1002
        mock_sender,
1003
        queue_message(Truly([&items](std::function<mavlink_message_t(
1004
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
1005
            return is_the_same_mission_item_int(items[0], fun(own_address, channel));
1006
        })));
1007

1008
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
1✔
1009

1010
    // We almost use up the max timeout in each cycle.
1011
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 0.8 * 1000.)));
1✔
1012
    timeout_handler.run_once();
1✔
1013

1014
    EXPECT_CALL(
2✔
1015
        mock_sender,
1016
        queue_message(Truly([&items](std::function<mavlink_message_t(
1017
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
1018
            return is_the_same_mission_item_int(items[1], fun(own_address, channel));
1019
        })));
1020

1021
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 1));
1✔
1022

1023
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 0.8 * 1000.)));
1✔
1024
    timeout_handler.run_once();
1✔
1025

1026
    EXPECT_CALL(
2✔
1027
        mock_sender,
1028
        queue_message(Truly([&items](std::function<mavlink_message_t(
1029
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
1030
            return is_the_same_mission_item_int(items[2], fun(own_address, channel));
1031
        })));
1032

1033
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 2));
1✔
1034

1035
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 0.8 * 1000.)));
1✔
1036
    timeout_handler.run_once();
1✔
1037

1038
    message_handler.process_message(
2✔
1039
        make_mission_ack(MAV_MISSION_TYPE_MISSION, MAV_MISSION_ACCEPTED));
2✔
1040

1041
    // We are finished and should have received the successful result.
1042
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
1043

1044
    mmt.do_work();
1✔
1045
    EXPECT_TRUE(mmt.is_idle());
1✔
1046
}
1✔
1047

1048
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionTimeoutAfterSendMissionItem)
4✔
1049
{
1050
    std::vector<ItemInt> items;
1✔
1051
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
1052
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
1053

1054
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
1055

1056
    std::promise<void> prom;
1✔
1057
    auto fut = prom.get_future();
1✔
1058

1059
    mmt.send_outgoing_items_async(
2✔
1060
        MAV_MISSION_TYPE_MISSION,
1061
        items,
1062
        target_address.system_id,
1✔
1063
        target_address.component_id,
1✔
1064
        [&prom](Result result) {
2✔
1065
            EXPECT_EQ(result, Result::Timeout);
1✔
1066
            ONCE_ONLY;
1✔
1067
            prom.set_value();
1✔
1068
        });
1✔
1069
    mmt.do_work();
1✔
1070

1071
    EXPECT_CALL(
2✔
1072
        mock_sender,
1073
        queue_message(Truly([&items](std::function<mavlink_message_t(
1074
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
1075
            return is_the_same_mission_item_int(items[0], fun(own_address, channel));
1076
        })));
1077

1078
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
1✔
1079

1080
    // Make sure single timeout does not trigger it yet.
1081
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1000. + 250)));
1✔
1082
    timeout_handler.run_once();
1✔
1083

1084
    EXPECT_EQ(fut.wait_for(std::chrono::milliseconds(50)), std::future_status::timeout);
1✔
1085

1086
    // But multiple do.
1087
    for (unsigned i = 0; i < (MavlinkMissionTransferServer::retries - 1); ++i) {
5✔
1088
        time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1000.)));
4✔
1089
        timeout_handler.run_once();
4✔
1090
    }
1091

1092
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
1093

1094
    // Ignore later (wrong) ack.
1095
    message_handler.process_message(
2✔
1096
        make_mission_ack(MAV_MISSION_TYPE_MISSION, MAV_MISSION_ACCEPTED));
2✔
1097

1098
    mmt.do_work();
1✔
1099
    EXPECT_TRUE(mmt.is_idle());
1✔
1100
}
1✔
1101

1102
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionDoesNotCrashOnRandomMessages)
4✔
1103
{
1104
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
1✔
1105

1106
    message_handler.process_message(
2✔
1107
        make_mission_ack(MAV_MISSION_TYPE_MISSION, MAV_MISSION_ACCEPTED));
2✔
1108

1109
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
1✔
1110
    timeout_handler.run_once();
1✔
1111

1112
    mmt.do_work();
1✔
1113
    EXPECT_TRUE(mmt.is_idle());
1✔
1114
}
1✔
1115

1116
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionCanBeCancelled)
4✔
1117
{
1118
    std::vector<ItemInt> items;
1✔
1119
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 0));
1✔
1120
    items.push_back(make_item(MAV_MISSION_TYPE_MISSION, 1));
1✔
1121

1122
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
1123

1124
    std::promise<void> prom;
1✔
1125
    auto fut = prom.get_future();
1✔
1126

1127
    auto transfer = mmt.send_outgoing_items_async(
1✔
1128
        MAV_MISSION_TYPE_MISSION,
1129
        items,
1130
        target_address.system_id,
1✔
1131
        target_address.component_id,
1✔
1132
        [&prom](Result result) {
2✔
1133
            EXPECT_EQ(result, Result::Cancelled);
1✔
1134
            ONCE_ONLY;
1✔
1135
            prom.set_value();
1✔
1136
        });
3✔
1137
    mmt.do_work();
1✔
1138

1139
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_MISSION, 0));
1✔
1140

1141
    EXPECT_CALL(
2✔
1142
        mock_sender,
1143
        queue_message(Truly([](std::function<mavlink_message_t(
1144
                                   MavlinkAddress mavlink_address, uint8_t channel)> fun) {
1145
            return is_correct_mission_ack(
1146
                MAV_MISSION_TYPE_MISSION,
1147
                MAV_MISSION_OPERATION_CANCELLED,
1148
                fun(own_address, channel));
1149
        })));
1150

1151
    auto ptr = transfer.lock();
1✔
1152
    EXPECT_TRUE(ptr);
1✔
1153
    if (ptr) {
1✔
1154
        ptr->cancel();
1✔
1155
    }
1156

1157
    // We are finished and should have received the successful result.
1158
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
1159

1160
    // We do not expect a timeout later though.
1161
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
1✔
1162
    timeout_handler.run_once();
1✔
1163

1164
    mmt.do_work();
1✔
1165
    EXPECT_TRUE(mmt.is_idle());
1✔
1166
}
1✔
1167

1168
TEST_F(MavlinkMissionTransferServerTest, SendOutgoingMissionNacksNonIntCase)
4✔
1169
{
1170
    std::vector<ItemInt> items;
1✔
1171
    items.push_back(make_item(MAV_MISSION_TYPE_FENCE, 0));
1✔
1172

1173
    ON_CALL(mock_sender, queue_message(_)).WillByDefault(Return(true));
1✔
1174

1175
    std::promise<void> prom;
1✔
1176
    auto fut = prom.get_future();
1✔
1177

1178
    mmt.send_outgoing_items_async(
2✔
1179
        MAV_MISSION_TYPE_FENCE,
1180
        items,
1181
        target_address.system_id,
1✔
1182
        target_address.component_id,
1✔
1183
        [&prom](Result result) {
2✔
1184
            EXPECT_EQ(result, Result::Success);
1✔
1185
            ONCE_ONLY;
1✔
1186
            prom.set_value();
1✔
1187
        });
1✔
1188
    mmt.do_work();
1✔
1189

1190
    EXPECT_CALL(
4✔
1191
        mock_sender,
1192
        queue_message(Truly([](std::function<mavlink_message_t(
1193
                                   MavlinkAddress mavlink_address, uint8_t channel)> fun) {
1194
            return is_correct_mission_ack(
1195
                MAV_MISSION_TYPE_FENCE, MAV_MISSION_UNSUPPORTED, fun(own_address, channel));
1196
        })))
1197
        .Times(1);
3✔
1198

1199
    // First the non-int wrong case comes in.
1200
    message_handler.process_message(make_mission_request(MAV_MISSION_TYPE_FENCE, 0));
1✔
1201

1202
    EXPECT_CALL(
2✔
1203
        mock_sender,
1204
        queue_message(Truly([&items](std::function<mavlink_message_t(
1205
                                         MavlinkAddress mavlink_address, uint8_t channel)> fun) {
1206
            return is_the_same_mission_item_int(items[0], fun(own_address, channel));
1207
        })));
1208

1209
    message_handler.process_message(make_mission_request_int(MAV_MISSION_TYPE_FENCE, 0));
1✔
1210
    message_handler.process_message(make_mission_ack(MAV_MISSION_TYPE_FENCE, MAV_MISSION_ACCEPTED));
1✔
1211

1212
    // We are finished and should have received the successful result.
1213
    EXPECT_EQ(fut.wait_for(std::chrono::seconds(1)), std::future_status::ready);
1✔
1214

1215
    // We do not expect a timeout later though.
1216
    time.sleep_for(std::chrono::milliseconds(static_cast<int>(timeout_s * 1.1 * 1000.)));
1✔
1217
    timeout_handler.run_once();
1✔
1218

1219
    mmt.do_work();
1✔
1220
    EXPECT_TRUE(mmt.is_idle());
1✔
1221
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc