mavtables  0.2.1
MAVLink router and firewall.
test_ConnectionFactory.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 
23 #include <catch.hpp>
24 
25 #include "ConnectionFactory.hpp"
26 #include "Filter.hpp"
27 #include "Packet.hpp"
28 #include "PacketVersion2.hpp"
29 #include "utility.hpp"
30 
31 #include "common.hpp"
32 #include "common_Packet.hpp"
33 
34 
35 using namespace std::chrono_literals;
36 
37 
38 TEST_CASE("ConnectionFactory's can be constructed.", "[ConnectionFactory]")
39 {
40  fakeit::Mock<Filter> mock_filter;
41  auto filter = mock_shared(mock_filter);
42  REQUIRE_NOTHROW(ConnectionFactory<>(filter));
43  REQUIRE_NOTHROW(ConnectionFactory<>(filter, true));
44  REQUIRE_NOTHROW(ConnectionFactory<>(filter, false));
45  SECTION("And ensures the given filter is not null.")
46  {
47  REQUIRE_THROWS_AS(ConnectionFactory<>(nullptr), std::invalid_argument);
48  REQUIRE_THROWS_WITH(
49  ConnectionFactory<>(nullptr), "Given filter pointer is null.");
50  }
51 }
52 
53 
54 TEST_CASE("ConnectionFactory's 'get' method returns a new connection.",
55  "[ConnectionFactory]")
56 {
57  auto heartbeat =
58  std::make_shared<packet_v2::Packet>(to_vector(HeartbeatV2()));
59  fakeit::Mock<Filter> mock_filter;
60  fakeit::When(Method(mock_filter, will_accept)
61  ).AlwaysDo([](auto & a, auto & b)
62  {
63  (void)a;
64  (void)b;
65  return std::pair<bool, int>(true, 0);
66  });
67  auto filter = mock_shared(mock_filter);
68  REQUIRE(filter != nullptr);
69  ConnectionFactory<> connection_factory(filter);
70  SECTION("with connection name")
71  {
72  std::unique_ptr<Connection> conn = connection_factory.get("CONNECTION");
73  REQUIRE(conn != nullptr);
74  REQUIRE(str(*conn) == "CONNECTION");
75  conn->add_address(MAVAddress("192.168"));
76  conn->send(heartbeat);
77  auto packet = conn->next_packet(0s);
78  REQUIRE(packet != nullptr);
79  REQUIRE(*packet == *heartbeat);
80  }
81  SECTION("without connection name")
82  {
83  std::unique_ptr<Connection> conn = connection_factory.get();
84  REQUIRE(conn != nullptr);
85  REQUIRE(str(*conn) == "unknown");
86  conn->add_address(MAVAddress("192.168"));
87  conn->send(heartbeat);
88  auto packet = conn->next_packet(0s);
89  REQUIRE(packet != nullptr);
90  REQUIRE(*packet == *heartbeat);
91  }
92 }
93 
94 
95 TEST_CASE("ConnectionFactory's 'wait_for_packet' method waits for a packet "
96  "on any of the connections created by the factory.",
97  "[ConnectionFactory]")
98 {
99  auto heartbeat =
100  std::make_shared<packet_v2::Packet>(to_vector(HeartbeatV2()));
101  fakeit::Mock<Filter> mock_filter;
102  fakeit::When(Method(mock_filter, will_accept)
103  ).AlwaysDo([](auto & a, auto & b)
104  {
105  (void)a;
106  (void)b;
107  return std::pair<bool, int>(true, 0);
108  });
109  auto filter = mock_shared(mock_filter);
110  REQUIRE(filter != nullptr);
111  ConnectionFactory<> connection_factory(filter);
112  std::unique_ptr<Connection> conn1 = connection_factory.get();
113  std::unique_ptr<Connection> conn2 = connection_factory.get();
114  conn1->add_address(MAVAddress("192.168"));
115  conn2->add_address(MAVAddress("192.168"));
116  SECTION("First connection.")
117  {
118  auto future = std::async(std::launch::async, [&]()
119  {
120  return connection_factory.wait_for_packet(10s);
121  });
122  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
123  conn1->send(heartbeat);
124  REQUIRE(future.wait_for(5ms) == std::future_status::ready);
125  REQUIRE(future.get());
126  }
127  SECTION("Second connection.")
128  {
129  auto future = std::async(std::launch::async, [&]()
130  {
131  return connection_factory.wait_for_packet(10s);
132  });
133  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
134  conn2->send(heartbeat);
135  REQUIRE(future.wait_for(5ms) == std::future_status::ready);
136  REQUIRE(future.get());
137  }
138  SECTION("Returns false on timeout.")
139  {
140  auto future = std::async(std::launch::async, [&]()
141  {
142  return connection_factory.wait_for_packet(1ms);
143  });
144  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
145  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
146  REQUIRE_FALSE(future.get());
147  }
148 }
std::string str(const T &object)
Definition: utility.hpp:128
TEST_VIRTUAL std::unique_ptr< C > get(std::string name="unknown")
TEST_VIRTUAL bool wait_for_packet(const std::chrono::nanoseconds &timeout)
def heartbeat(mav)
Definition: logger.py:42
TEST_VIRTUAL std::shared_ptr< const Packet > next_packet(const std::chrono::nanoseconds &timeout=std::chrono::nanoseconds(0))
Definition: Connection.cpp:303
std::shared_ptr< T > mock_shared(fakeit::Mock< T > &mock)
Definition: common.hpp:33
TEST_CASE("ConnectionFactory's can be constructed.", "[ConnectionFactory]")
TEST_VIRTUAL void add_address(MAVAddress address)
Definition: Connection.cpp:281
TEST_VIRTUAL void send(std::shared_ptr< const Packet > packet)
Definition: Connection.cpp:327