mavtables  0.2.1
MAVLink router and firewall.
test_SerialInterface.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 <algorithm>
19 #include <chrono>
20 #include <cstdint>
21 #include <set>
22 #include <stdexcept>
23 #include <vector>
24 
25 #include <catch.hpp>
26 #include <fakeit.hpp>
27 
28 #include "Connection.hpp"
29 #include "ConnectionPool.hpp"
30 #include "Packet.hpp"
31 #include "PacketVersion2.hpp"
32 #include "SerialInterface.hpp"
33 #include "SerialPort.hpp"
34 #include "utility.hpp"
35 
36 #include "common.hpp"
37 #include "common_Packet.hpp"
38 
39 
40 using namespace std::chrono_literals;
41 
42 
43 TEST_CASE("SerialInterface's can be constructed.", "[SerialInterface]")
44 {
45  fakeit::Mock<SerialPort> mock_port;
46  fakeit::Mock<ConnectionPool> mock_pool;
47  fakeit::Mock<Connection> mock_connection;
48  fakeit::Fake(Method(mock_pool, add));
49  auto port = mock_unique(mock_port);
50  auto pool = mock_shared(mock_pool);
51  auto connection = mock_unique(mock_connection);
52  SECTION("When all inputs are valid, registers connection with pool.")
53  {
54  Connection *conn = nullptr;
55  fakeit::When(Method(mock_pool, add)).AlwaysDo([&](auto a)
56  {
57  conn = a.lock().get();
58  });
59  REQUIRE_NOTHROW(
60  SerialInterface(std::move(port), pool, std::move(connection)));
61  fakeit::Verify(Method(mock_pool, add)).Once();
62  REQUIRE(conn == &mock_connection.get());
63  }
64  SECTION("Ensures the serial port pointer is not null.")
65  {
66  REQUIRE_THROWS_AS(
67  SerialInterface(nullptr, pool, std::move(connection)),
68  std::invalid_argument);
69  connection = mock_unique(mock_connection);
70  REQUIRE_THROWS_WITH(
71  SerialInterface(nullptr, pool, std::move(connection)),
72  "Given serial port pointer is null.");
73  }
74  SECTION("Ensures the connection pool pointer is not null.")
75  {
76  REQUIRE_THROWS_AS(
77  SerialInterface(std::move(port), nullptr, std::move(connection)),
78  std::invalid_argument);
79  port = mock_unique(mock_port);
80  connection = mock_unique(mock_connection);
81  REQUIRE_THROWS_WITH(
82  SerialInterface(std::move(port), nullptr, std::move(connection)),
83  "Given connection pool pointer is null.");
84  }
85  SECTION("Ensures the connection pointer is not null.")
86  {
87  REQUIRE_THROWS_AS(
88  SerialInterface(std::move(port), pool, nullptr),
89  std::invalid_argument);
90  port = mock_unique(mock_port);
91  REQUIRE_THROWS_WITH(
92  SerialInterface(std::move(port), pool, nullptr),
93  "Given connection pointer is null.");
94  }
95 }
96 
97 
98 TEST_CASE("SerialInterface's 'receive_packet' method.", "[SerialInterface]")
99 {
100  // MAVLink packets.
101  auto heartbeat =
102  std::make_shared<packet_v2::Packet>(to_vector(HeartbeatV2()));
103  auto encapsulated_data =
104  std::make_shared<packet_v2::Packet>(to_vector(EncapsulatedDataV2()));
105  // Serial port
106  SerialPort serial_port;
107  fakeit::Mock<SerialPort> mock_port(serial_port);
108  auto port = mock_unique(mock_port);
109  using read_type =
110  void(std::back_insert_iterator<std::vector<uint8_t>>,
111  const std::chrono::nanoseconds &);
112  // Pool
113  fakeit::Mock<ConnectionPool> mock_pool;
114  auto pool = mock_shared(mock_pool);
115  fakeit::Fake(Method(mock_pool, add));
116  std::multiset<packet_v2::Packet,
117  bool(*)(const packet_v2::Packet &, const packet_v2::Packet &)>
118  send_packets([](const auto & a, const auto & b)
119  {
120  return a.data() < b.data();
121  });
122  fakeit::When(Method(mock_pool, send)).AlwaysDo([&](auto & a)
123  {
124  const Packet *packet = a.get();
125  send_packets.insert(
127  *dynamic_cast<const packet_v2::Packet *>(packet)));
128  });
129  // Connection
130  fakeit::Mock<Connection> mock_connection;
131  auto connection = mock_unique(mock_connection);
132  fakeit::Fake(Method(mock_connection, add_address));
133  // Interface
134  SerialInterface serial(std::move(port), pool, std::move(connection));
135  std::chrono::nanoseconds timeout = 250ms;
136  SECTION("No packet received.")
137  {
138  // Mocks
139  fakeit::When(OverloadedMethod(mock_port, read, read_type)
140  ).AlwaysDo([](auto a, auto b)
141  {
142  (void)a;
143  (void)b;
144  });
145  // Test
146  serial.receive_packet(timeout);
147  // Verification
148  fakeit::Verify(OverloadedMethod(mock_port, read, read_type).Matching(
149  [&](auto a, auto b)
150  {
151  (void)a;
152  return b == 250ms;
153  })).Once();
154  fakeit::Verify(Method(mock_connection, add_address)).Exactly(0);
155  fakeit::Verify(Method(mock_pool, send)).Exactly(0);
156  }
157  SECTION("Partial packet received.")
158  {
159  // Mocks
160  fakeit::When(OverloadedMethod(mock_port, read, read_type)
161  ).AlwaysDo([](auto a, auto b)
162  {
163  (void)b;
164  auto vec = to_vector(HeartbeatV2());
165  std::copy(vec.begin(), vec.end() - 1, a);
166  });
167  // Test
168  serial.receive_packet(timeout);
169  // Verification
170  fakeit::Verify(OverloadedMethod(mock_port, read, read_type).Matching(
171  [&](auto a, auto b)
172  {
173  (void)a;
174  return b == 250ms;
175  })).Once();
176  fakeit::Verify(Method(mock_connection, add_address)).Exactly(0);
177  fakeit::Verify(Method(mock_pool, send)).Exactly(0);
178  }
179  SECTION("Full packet received.")
180  {
181  // Mocks
182  fakeit::When(OverloadedMethod(mock_port, read, read_type)
183  ).AlwaysDo([](auto a, auto b)
184  {
185  (void)b;
186  auto vec = to_vector(HeartbeatV2());
187  std::copy(vec.begin(), vec.end(), a);
188  });
189  // Test
190  serial.receive_packet(timeout);
191  // Verification
192  fakeit::Verify(OverloadedMethod(mock_port, read, read_type).Matching(
193  [&](auto a, auto b)
194  {
195  (void)a;
196  return b == 250ms;
197  })).Once();
198  fakeit::Verify(Method(mock_connection, add_address
199  ).Using(MAVAddress("127.1"))).Exactly(1);
200  fakeit::Verify(Method(mock_pool, send)).Exactly(1);
201  REQUIRE(send_packets.count(*heartbeat) == 1);
202  auto it = send_packets.find(*heartbeat);
203  REQUIRE(it != send_packets.end());
204  REQUIRE(it->connection() != nullptr);
205  }
206  SECTION("Multiple packets received (same MAVLink address).")
207  {
208  // Mocks
209  fakeit::When(OverloadedMethod(mock_port, read, read_type)
210  ).AlwaysDo([](auto a, auto b)
211  {
212  (void)b;
213  auto vec = to_vector(HeartbeatV2());
214  std::copy(vec.begin(), vec.end(), a);
215  });
216  // Test
217  serial.receive_packet(timeout);
218  serial.receive_packet(timeout);
219  // Verification
220  fakeit::Verify(OverloadedMethod(mock_port, read, read_type).Matching(
221  [&](auto a, auto b)
222  {
223  (void)a;
224  return b == 250ms;
225  })).Exactly(2);
226  fakeit::Verify(Method(mock_connection, add_address
227  ).Using(MAVAddress("127.1"))).Exactly(2);
228  fakeit::Verify(Method(mock_pool, send)).Exactly(2);
229  REQUIRE(send_packets.count(*heartbeat) == 2);
230  auto it = send_packets.find(*heartbeat);
231  REQUIRE(it != send_packets.end());
232  REQUIRE(it->connection() != nullptr);
233  it++;
234  REQUIRE(it != send_packets.end());
235  REQUIRE(it->connection() != nullptr);
236  }
237  SECTION("Multiple packets received (different MAVLink address).")
238  {
239  // Mocks
240  fakeit::When(OverloadedMethod(mock_port, read, read_type)
241  ).Do([](auto a, auto b)
242  {
243  (void)b;
244  auto vec = to_vector(HeartbeatV2());
245  std::copy(vec.begin(), vec.end(), a);
246  }).Do([](auto a, auto b)
247  {
248  (void)b;
249  auto vec = to_vector(EncapsulatedDataV2());
250  std::copy(vec.begin(), vec.end(), a);
251  });
252  // Test
253  serial.receive_packet(timeout);
254  serial.receive_packet(timeout);
255  // Verification
256  fakeit::Verify(OverloadedMethod(mock_port, read, read_type).Matching(
257  [&](auto a, auto b)
258  {
259  (void)a;
260  return b == 250ms;
261  })).Exactly(2);
262  fakeit::Verify(Method(mock_connection, add_address
263  ).Using(MAVAddress("127.1"))).Exactly(1);
264  fakeit::Verify(Method(mock_connection, add_address
265  ).Using(MAVAddress("224.255"))).Exactly(1);
266  fakeit::Verify(Method(mock_pool, send)).Exactly(2);
267  REQUIRE(send_packets.count(*heartbeat) == 1);
268  REQUIRE(send_packets.count(*encapsulated_data) == 1);
269  auto it = send_packets.find(*heartbeat);
270  REQUIRE(it != send_packets.end());
271  REQUIRE(it->connection() != nullptr);
272  it = send_packets.find(*encapsulated_data);
273  REQUIRE(it != send_packets.end());
274  REQUIRE(it->connection() != nullptr);
275  }
276  SECTION("Partial packets should be combined and parsed.")
277  {
278  // Mocks
279  fakeit::When(OverloadedMethod(mock_port, read, read_type)
280  ).Do([](auto a, auto b)
281  {
282  (void)b;
283  auto vec = to_vector(EncapsulatedDataV2());
284  std::copy(vec.begin(), vec.end() - 10, a);
285  }).Do([](auto a, auto b)
286  {
287  (void)b;
288  auto vec = to_vector(EncapsulatedDataV2());
289  std::copy(vec.end() - 10, vec.end(), a);
290  });
291  // Test
292  serial.receive_packet(timeout);
293  serial.receive_packet(timeout);
294  // Verification
295  fakeit::Verify(OverloadedMethod(mock_port, read, read_type).Matching(
296  [&](auto a, auto b)
297  {
298  (void)a;
299  return b == 250ms;
300  })).Exactly(2);
301  fakeit::Verify(Method(mock_connection, add_address
302  ).Using(MAVAddress("224.255"))).Exactly(1);
303  fakeit::Verify(Method(mock_pool, send)).Exactly(1);
304  REQUIRE(send_packets.count(*encapsulated_data) == 1);
305  auto it = send_packets.find(*encapsulated_data);
306  REQUIRE(it != send_packets.end());
307  REQUIRE(it->connection() != nullptr);
308  }
309 }
310 
311 
312 TEST_CASE("SerialInterface's 'send_packet' method.", "[SerialInterface]")
313 {
314  // MAVLink packets.
315  auto heartbeat =
316  std::make_shared<packet_v2::Packet>(to_vector(HeartbeatV2()));
317  auto encapsulated_data =
318  std::make_shared<packet_v2::Packet>(to_vector(EncapsulatedDataV2()));
319  // Serial port
320  SerialPort serial_port;
321  fakeit::Mock<SerialPort> mock_port(serial_port);
322  auto port = mock_unique(mock_port);
323  using write_type =
324  void(std::vector<uint8_t>::const_iterator first,
325  std::vector<uint8_t>::const_iterator last);
326  std::multiset<std::vector<uint8_t>> write_bytes;
327  fakeit::When(OverloadedMethod(mock_port, write, write_type)).AlwaysDo(
328  [&](auto a, auto b)
329  {
330  std::vector<uint8_t> vec;
331  std::copy(a, b, std::back_inserter(vec));
332  write_bytes.insert(vec);
333  });
334  // Pool
335  fakeit::Mock<ConnectionPool> mock_pool;
336  auto pool = mock_shared(mock_pool);
337  fakeit::Fake(Method(mock_pool, add));
338  // Connection
339  fakeit::Mock<Connection> mock_connection;
340  auto connection = mock_unique(mock_connection);
341  // Interface
342  SerialInterface serial(std::move(port), pool, std::move(connection));
343  std::chrono::nanoseconds timeout = 250ms;
344  SECTION("No packets, timeout.")
345  {
346  // Mocks
347  fakeit::When(Method(mock_connection, next_packet)).Return(nullptr);
348  // Test
349  serial.send_packet(timeout);
350  // Verification
351  fakeit::Verify(
352  Method(mock_connection, next_packet).Using(250ms)).Once();
353  fakeit::Verify(
354  OverloadedMethod(mock_port, write, write_type)).Exactly(0);
355  }
356  SECTION("Single packet.")
357  {
358  // Mocks
359  fakeit::When(Method(mock_connection, next_packet)).Return(heartbeat);
360  // Test
361  serial.send_packet(timeout);
362  // Verification
363  fakeit::Verify(
364  Method(mock_connection, next_packet).Using(250ms)).Once();
365  fakeit::Verify(
366  OverloadedMethod(mock_port, write, write_type)).Exactly(1);
367  REQUIRE(write_bytes.count(heartbeat->data()) == 1);
368  }
369  SECTION("Multiple packets.")
370  {
371  // Mocks
372  fakeit::When(Method(mock_connection, next_packet)
373  ).Return(heartbeat).Return(encapsulated_data);
374  // Test
375  serial.send_packet(timeout);
376  // Verification
377  fakeit::Verify(
378  Method(mock_connection, next_packet).Using(250ms)).Once();
379  fakeit::Verify(
380  OverloadedMethod(mock_port, write, write_type)).Exactly(1);
381  REQUIRE(write_bytes.count(heartbeat->data()) == 1);
382  // Test
383  serial.send_packet(timeout);
384  // Verification
385  fakeit::Verify(
386  Method(mock_connection, next_packet).Using(250ms)).Exactly(2);
387  fakeit::Verify(
388  OverloadedMethod(mock_port, write, write_type)).Exactly(2);
389  REQUIRE(write_bytes.count(heartbeat->data()) == 1);
390  REQUIRE(write_bytes.count(encapsulated_data->data()) == 1);
391  }
392 }
393 
394 
395 TEST_CASE("SerialInterface's are printable.", "[SerialInterface]")
396 {
397  fakeit::Mock<ConnectionPool> mock_pool;
398  fakeit::Mock<Connection> mock_connection;
399  fakeit::Fake(Method(mock_pool, add));
400  auto pool = mock_shared(mock_pool);
401  auto connection = mock_unique(mock_connection);
402  auto port = std::make_unique<SerialPort>();
403  SerialInterface serial(std::move(port), pool, std::move(connection));
404  REQUIRE(str(serial) == "unknown serial port");
405 }
void receive_packet(const std::chrono::nanoseconds &timeout) final
std::string str(const T &object)
Definition: utility.hpp:128
TEST_CASE("SerialInterface's can be constructed.", "[SerialInterface]")
void send_packet(const std::chrono::nanoseconds &timeout) final
def heartbeat(mav)
Definition: logger.py:42
std::shared_ptr< T > mock_shared(fakeit::Mock< T > &mock)
Definition: common.hpp:33
std::unique_ptr< T > mock_unique(fakeit::Mock< T > &mock)
Definition: common.hpp:46