mavtables  0.2.1
MAVLink router and firewall.
test_PacketQueue.cpp
Go to the documentation of this file.
1 // MAVLink router and firewall.
2 // Copyright (C) 2018 Michael R. Shannon <mrshannon.aerospace@gmail.com>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 
18 #include <chrono>
19 #include <future>
20 #include <memory>
21 #include <stdexcept>
22 #include <thread>
23 
24 #include <catch.hpp>
25 
26 #include <Packet.hpp>
27 #include <PacketQueue.hpp>
28 #include "PacketVersion2.hpp"
29 
30 #include "common_Packet.hpp"
31 
32 
33 using namespace std::chrono_literals;
34 
35 
36 TEST_CASE("PacketQueue's can be constructed.", "[AddressPool]")
37 {
38  SECTION("Without a push callback.")
39  {
40  REQUIRE_NOTHROW(PacketQueue());
41  }
42  SECTION("With a push callback.")
43  {
44  PacketQueue pq([]() {});
45  auto ping = std::make_shared<packet_v2::Packet>(to_vector(PingV2()));
46  pq.push(ping);
47  }
48 }
49 
50 
51 TEST_CASE("PacketQueue's 'push' adds a packet to the queue.", "[PacketQueue]")
52 {
53  SECTION("Ensures the packet is not null.")
54  {
55  PacketQueue queue;
56  REQUIRE_THROWS_AS(queue.push(nullptr), std::invalid_argument);
57  REQUIRE_THROWS_WITH(
58  queue.push(nullptr), "Given packet pointer is null.");
59  }
60  SECTION("Calls the push callback.")
61  {
62  auto ping = std::make_shared<packet_v2::Packet>(to_vector(PingV2()));
63  bool called = false;
64  PacketQueue queue([&]()
65  {
66  called = true;
67  });
68  REQUIRE_FALSE(called);
69  queue.push(ping);
70  REQUIRE(called);
71  }
72 }
73 
74 
75 TEST_CASE("PacketQueue's 'empty' method determines if the queue is empty or "
76  "not.", "[PacketQueue]")
77 {
78  auto ping = std::make_shared<packet_v2::Packet>(to_vector(PingV2()));
79  PacketQueue queue;
80  REQUIRE(queue.empty());
81  queue.push(ping);
82  REQUIRE_FALSE(queue.empty());
83 }
84 
85 
86 TEST_CASE("PacketQueue's can be managed with 'push' and 'pop' methods.",
87  "[PacketQueue]")
88 {
89  auto heartbeat =
90  std::make_shared<packet_v2::Packet>(to_vector(HeartbeatV2()));
91  auto ping =
92  std::make_shared<packet_v2::Packet>(to_vector(PingV2()));
93  auto set_mode =
94  std::make_shared<packet_v2::Packet>(to_vector(SetModeV2()));
95  auto mission_set_current =
96  std::make_shared<packet_v2::Packet>(to_vector(MissionSetCurrentV2()));
97  auto encapsulated_data =
98  std::make_shared<packet_v2::Packet>(to_vector(EncapsulatedDataV2()));
99  auto param_ext_request_list =
100  std::make_shared<packet_v2::Packet>(to_vector(ParamExtRequestListV2()));
101  PacketQueue queue;
102  SECTION("Maintains order among the same priority")
103  {
104  queue.push(heartbeat);
105  queue.push(ping, 0);
106  queue.push(set_mode);
107  queue.push(mission_set_current, 0);
108  queue.push(encapsulated_data);
109  queue.push(param_ext_request_list, 0);
110  // HEARTBEAT
111  auto packet = queue.pop(0s);
112  REQUIRE(packet != nullptr);
113  REQUIRE(*packet == *heartbeat);
114  // PING
115  packet = queue.pop(0s);
116  REQUIRE(packet != nullptr);
117  REQUIRE(*packet == *ping);
118  // SET_MODE
119  packet = queue.pop(0s);
120  REQUIRE(packet != nullptr);
121  REQUIRE(*packet == *set_mode);
122  // MISSION_SET_CURRENT
123  packet = queue.pop(0s);
124  REQUIRE(packet != nullptr);
125  REQUIRE(*packet == *mission_set_current);
126  // ENCAPSULATED_DATA
127  packet = queue.pop(0s);
128  REQUIRE(packet != nullptr);
129  REQUIRE(*packet == *encapsulated_data);
130  // PARAM_EXT_REQUEST_LIST
131  packet = queue.pop(0s);
132  REQUIRE(packet != nullptr);
133  REQUIRE(*packet == *param_ext_request_list);
134  }
135  SECTION("Maintains priority order.")
136  {
137  queue.push(heartbeat, -1);
138  queue.push(ping, 0);
139  queue.push(set_mode, 1);
140  queue.push(mission_set_current, -3);
141  queue.push(encapsulated_data, -2);
142  queue.push(param_ext_request_list, 3);
143  // PARAM_EXT_REQUEST_LIST
144  auto packet = queue.pop(0s);
145  REQUIRE(packet != nullptr);
146  REQUIRE(*packet == *param_ext_request_list);
147  // SET_MODE
148  packet = queue.pop(0s);
149  REQUIRE(packet != nullptr);
150  REQUIRE(*packet == *set_mode);
151  // PING
152  packet = queue.pop(0s);
153  REQUIRE(packet != nullptr);
154  REQUIRE(*packet == *ping);
155  // HEARTBEAT
156  packet = queue.pop(0s);
157  REQUIRE(packet != nullptr);
158  REQUIRE(*packet == *heartbeat);
159  // ENCAPSULATED_DATA
160  packet = queue.pop(0s);
161  REQUIRE(packet != nullptr);
162  REQUIRE(*packet == *encapsulated_data);
163  // MISSION_SET_CURRENT
164  packet = queue.pop(0s);
165  REQUIRE(packet != nullptr);
166  REQUIRE(*packet == *mission_set_current);
167  }
168  SECTION("Maintains order among the same priority as well as "
169  "priority order.")
170  {
171  queue.push(heartbeat);
172  queue.push(ping, 2);
173  queue.push(set_mode);
174  queue.push(mission_set_current, 2);
175  queue.push(encapsulated_data);
176  queue.push(param_ext_request_list, 2);
177  // PING
178  auto packet = queue.pop();
179  REQUIRE(packet != nullptr);
180  REQUIRE(*packet == *ping);
181  // MISSION_SET_CURRENT
182  packet = queue.pop(0s);
183  REQUIRE(packet != nullptr);
184  REQUIRE(*packet == *mission_set_current);
185  // PARAM_EXT_REQUEST_LIST
186  packet = queue.pop(0s);
187  REQUIRE(packet != nullptr);
188  REQUIRE(*packet == *param_ext_request_list);
189  // HEARTBEAT
190  packet = queue.pop(0s);
191  REQUIRE(packet != nullptr);
192  REQUIRE(*packet == *heartbeat);
193  // SET_MODE
194  packet = queue.pop(0s);
195  REQUIRE(packet != nullptr);
196  REQUIRE(*packet == *set_mode);
197  // ENCAPSULATED_DATA
198  packet = queue.pop(0s);
199  REQUIRE(packet != nullptr);
200  REQUIRE(*packet == *encapsulated_data);
201  }
202 }
203 
204 
205 TEST_CASE("PacketQueue's 'pop' method blocks by default.", "[PacketQueue]")
206 {
207  auto ping = std::make_shared<packet_v2::Packet>(to_vector(PingV2()));
208  PacketQueue queue;
209  SECTION("And will be released when a packet becomes available.")
210  {
211  auto future = std::async(std::launch::async, [&]()
212  {
213  return queue.pop();
214  });
215  REQUIRE(future.wait_for(0s) != std::future_status::ready);
216  queue.push(ping);
217  auto result = future.get();
218  REQUIRE(result != nullptr);
219  REQUIRE(*result == *ping);
220  }
221  SECTION("And will be released when the 'close' method is called.")
222  {
223  auto future1 = std::async(std::launch::async, [&]()
224  {
225  return queue.pop();
226  });
227  auto future2 = std::async(std::launch::async, [&]()
228  {
229  return queue.pop();
230  });
231  REQUIRE(future1.wait_for(0s) != std::future_status::ready);
232  REQUIRE(future2.wait_for(0s) != std::future_status::ready);
233  queue.close();
234  REQUIRE(future1.get() == nullptr);
235  REQUIRE(future2.get() == nullptr);
236  }
237 }
238 
239 
240 TEST_CASE("PacketQueue's 'pop' method optionally has a timeout.",
241  "[PacketQueue]")
242 {
243  auto ping = std::make_shared<packet_v2::Packet>(to_vector(PingV2()));
244  PacketQueue queue;
245  SECTION("And will be released when a packet becomes available.")
246  {
247  auto future = std::async(std::launch::async, [&]()
248  {
249  return queue.pop(10s);
250  });
251  auto status = future.wait_for(0s);
252  REQUIRE(status != std::future_status::ready);
253  queue.push(ping);
254  auto result = future.get();
255  REQUIRE(result != nullptr);
256  REQUIRE(*result == *ping);
257  }
258  SECTION("And will be released when the timeout expires.")
259  {
260  auto future = std::async(std::launch::async, [&]()
261  {
262  return queue.pop(1ms);
263  });
264  auto status = future.wait_for(0s);
265  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
266  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
267  REQUIRE(future.get() == nullptr);
268  }
269  SECTION("And will be released when the 'close' method is called.")
270  {
271  auto future1 = std::async(std::launch::async, [&]()
272  {
273  return queue.pop(10s);
274  });
275  auto future2 = std::async(std::launch::async, [&]()
276  {
277  return queue.pop(10s);
278  });
279  REQUIRE(future1.wait_for(0s) != std::future_status::ready);
280  REQUIRE(future2.wait_for(0s) != std::future_status::ready);
281  queue.close();
282  REQUIRE(future1.get() == nullptr);
283  REQUIRE(future2.get() == nullptr);
284  }
285 }
286 
287 
288 TEST_CASE("PacketQueue's 'pop' method is non blocking when given a 0 second "
289  "timeout.", "[PacketQueue]")
290 {
291  auto ping = std::make_shared<packet_v2::Packet>(to_vector(PingV2()));
292  PacketQueue queue;
293  SECTION("Returns the packet when it is available.")
294  {
295  queue.push(ping);
296  auto packet = queue.pop(0s);
297  REQUIRE(packet != nullptr);
298  REQUIRE(*packet == *ping);
299  }
300  SECTION("Returns nullptr when the queue is empty.")
301  {
302  REQUIRE(queue.pop(0s) == nullptr);
303  }
304 }
TEST_VIRTUAL void push(std::shared_ptr< const Packet > packet, int priority=0)
TEST_CASE("PacketQueue's can be constructed.", "[AddressPool]")
def heartbeat(mav)
Definition: logger.py:42
auto ping
Definition: test_Call.cpp:229