mavtables  0.2.1
MAVLink router and firewall.
test_InterfaceThreader.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 <atomic>
19 #include <chrono>
20 #include <memory>
21 #include <vector>
22 
23 #include <catch.hpp>
24 
25 #include "ConnectionPool.hpp"
26 #include "Interface.hpp"
27 #include "InterfaceThreader.hpp"
28 
29 
30 using namespace std::chrono_literals;
31 
32 
33 namespace
34 {
35 
36 #ifdef __clang__
37  #pragma clang diagnostic push
38  #pragma clang diagnostic ignored "-Wweak-vtables"
39 #endif
40 
41  // Subclass of Interface used for testing the abstract class Interface.
42  class InterfaceTestClass : public Interface
43  {
44  public:
45  InterfaceTestClass(
46  std::atomic<unsigned int> &tx_counter_,
47  std::atomic<unsigned int> &rx_counter_)
48  : tx_counter(tx_counter_), rx_counter(rx_counter_)
49  {
50  }
51  void send_packet(
52  const std::chrono::nanoseconds &timeout =
53  std::chrono::nanoseconds(100000)) final
54  {
55  std::this_thread::sleep_for(timeout);
56  ++tx_counter;
57  }
58  void receive_packet(
59  const std::chrono::nanoseconds &timeout =
60  std::chrono::nanoseconds(100000)) final
61  {
62  std::this_thread::sleep_for(timeout);
63  ++rx_counter;
64  }
65 
66  protected:
67  // No point in testing this.
68  // LCOV_EXCL_START
69  std::ostream &print_(std::ostream &os) const final
70  {
71  os << "interface test class";
72  return os;
73  }
74  // LCOV_EXCL_STOP
75 
76  private:
77  std::atomic<unsigned int> &tx_counter;
78  std::atomic<unsigned int> &rx_counter;
79 
80  };
81 
82 #ifdef __clang__
83  #pragma clang diagnostic pop
84 #endif
85 
86 }
87 
88 
89 TEST_CASE("InterfaceThreader's can be constructed.", "[InterfaceThreader]")
90 {
91  std::atomic<unsigned int> tx_count(0);
92  std::atomic<unsigned int> rx_count(0);
93  SECTION("With delayed start.")
94  {
95  REQUIRE_NOTHROW(
97  std::make_unique<InterfaceTestClass>(tx_count, rx_count),
99  }
100  SECTION("With immediate start.")
101  {
102  REQUIRE_NOTHROW(
104  std::make_unique<InterfaceTestClass>(tx_count, rx_count)));
105  }
106 }
107 
108 
109 TEST_CASE("InterfaceThreader's run Interface::send_packet and "
110  "Interface::receive_packet methods of the contained "
111  "Interface repeatedly.", "[InterfaceThreader]")
112 {
113  std::atomic<unsigned int> tx_count(0);
114  std::atomic<unsigned int> rx_count(0);
115  SECTION("With delayed start.")
116  {
117  REQUIRE(tx_count == 0);
118  REQUIRE(rx_count == 0);
119  InterfaceThreader threader(
120  std::make_unique<InterfaceTestClass>(tx_count, rx_count),
122  REQUIRE(tx_count == 0);
123  REQUIRE(rx_count == 0);
124  threader.start();
125  std::this_thread::sleep_for(10ms);
126  threader.shutdown();
127  auto tx_count_ = tx_count.load();
128  auto rx_count_ = rx_count.load();
129  REQUIRE(tx_count > 0);
130  REQUIRE(rx_count > 0);
131  std::this_thread::sleep_for(10ms);
132  REQUIRE(tx_count == tx_count_);
133  REQUIRE(rx_count == rx_count_);
134  }
135  SECTION("With immediate start (manual shutdown).")
136  {
137  REQUIRE(tx_count == 0);
138  REQUIRE(rx_count == 0);
139  InterfaceThreader threader(
140  std::make_unique<InterfaceTestClass>(tx_count, rx_count), 1us);
141  std::this_thread::sleep_for(10ms);
142  threader.shutdown();
143  auto tx_count_ = tx_count.load();
144  auto rx_count_ = rx_count.load();
145  REQUIRE(tx_count > 0);
146  REQUIRE(rx_count > 0);
147  std::this_thread::sleep_for(10ms);
148  REQUIRE(tx_count == tx_count_);
149  REQUIRE(rx_count == rx_count_);
150  }
151  SECTION("With immediate start (RAII shutdown).")
152  {
153  REQUIRE(tx_count == 0);
154  REQUIRE(rx_count == 0);
155  {
156  InterfaceThreader threader(
157  std::make_unique<InterfaceTestClass>(tx_count, rx_count), 1us);
158  std::this_thread::sleep_for(10ms);
159  }
160  auto tx_count_ = tx_count.load();
161  auto rx_count_ = rx_count.load();
162  REQUIRE(tx_count > 0);
163  REQUIRE(rx_count > 0);
164  std::this_thread::sleep_for(10ms);
165  REQUIRE(tx_count == tx_count_);
166  REQUIRE(rx_count == rx_count_);
167  }
168 }
TEST_CASE("InterfaceThreader's can be constructed.", "[InterfaceThreader]")
Delay starting, use start to launch threads.
def send_packet(mav, packet, system=0, component=0)