udp_socket_test.cpp
Go to the documentation of this file.
1 #include "../../src/socket/udp_socket.h"
2 
3 #include <fruit/fruit.h>
4 #include <gtest/gtest.h>
5 
6 #include <algorithm>
7 #include <boost/array.hpp>
8 #include <boost/asio.hpp>
9 #include <functional>
10 #include <iostream>
11 #include <iterator>
12 #include <memory>
13 #include <unordered_map>
14 
15 #include "std_msgs/UInt8MultiArray.h"
16 
17 using boost::asio::ip::address;
18 using boost::asio::ip::udp;
19 using fruit::Component;
20 using fruit::createComponent;
21 using fruit::Injector;
22 
23 // UDPでデータを受信したらcallbackが発火する部分のテスト
24 TEST(TestSuite, socket_callback) {
25  ros::NodeHandle nh;
26 
27  // callbackが発火したことを示すflag
28  bool is_received = false;
29  // 最終的に評価に使う、受信データを格納するvector
30  std::vector<uint8_t> received_vec;
31 
32  // socketに渡すcallback
33  auto func_ptr = std::make_shared<std::function<void(std::vector<uint8_t>)>>(
34  [&](std::vector<uint8_t> vec) {
35  // 受信データを格納し、フラグを立てる
36  copy(vec.begin(), vec.end(), back_inserter(received_vec));
37  is_received = true;
38  });
39 
40  // objectを作成し、受信スレッドを開始
41  Injector<SocketFactory> injector(getUdpSocketComponent);
42  SocketFactory socketFactory(injector);
43  // データは送信しないのでportは何でも良い
44  auto source = socketFactory(udp::endpoint(udp::v4(), 0), func_ptr);
45  source->Start();
46 
47  // 受信スレッドに対してデータを送信
48  unsigned short port = source->Port();
49  std::thread sending_thread([&] {
50  ros::Rate wait_rate(10);
51  wait_rate.sleep();
52  boost::asio::io_service io_service;
53  udp::resolver resolver(io_service);
54  udp::endpoint receiver_endpoint(udp::v4(), port);
55 
56  udp::socket socket(io_service);
57  socket.open(udp::v4());
58 
59  std::vector<uint8_t> cvec = {0, 1, 2, 3, 4};
60  auto buf = boost::asio::buffer(cvec);
61  socket.send_to(buf, receiver_endpoint);
62  });
63 
64  // データの受け渡しが完了するまでspinする
65  ros::Rate loop_rate(100);
66  while (!ros::isShuttingDown() && !is_received) {
67  ros::spinOnce();
68  loop_rate.sleep();
69  }
70 
71  // 受信スレッドの停止
72  source->Stop();
73 
74  sending_thread.join();
75 
76  // 送信データはindexとvalueが一致した数列
77  for (int i = 0; i < received_vec.size(); i++) {
78  ASSERT_EQ(received_vec[i], i);
79  }
80 }
81 
82 // UDPでデータを受信したらcallbackが発火する部分のテスト
83 // 複数回受信できることを確認
84 TEST(TestSuite, socket_callback_twice) {
85  ros::NodeHandle nh;
86 
87  // callbackが発火したことを示すflag
88  bool is_received = false;
89  // 最終的に評価に使う、受信データを格納するvector
90  std::vector<uint8_t> received_vec;
91  // 2回目でループを抜けるためのcounter
92  int counter = 0;
93 
94  // socketに渡すcallback
95  auto func_ptr = std::make_shared<std::function<void(std::vector<uint8_t>)>>(
96  [&](std::vector<uint8_t> vec) {
97  // 受信データを格納し、フラグを立てる
98  counter += 1;
99  if (counter == 2) {
100  copy(vec.begin(), vec.end(), back_inserter(received_vec));
101  is_received = true;
102  }
103  });
104 
105  // objectを作成し、受信スレッドを開始
106  Injector<SocketFactory> injector(getUdpSocketComponent);
107  SocketFactory socketFactory(injector);
108  // データは送信しないのでportは何でも良い
109  auto source = socketFactory(udp::endpoint(udp::v4(), 0), func_ptr);
110  source->Start();
111 
112  // 受信スレッドに対してデータを送信
113  unsigned short port = source->Port();
114  std::thread sending_thread([&] {
115  ros::Rate wait_rate(10);
116  wait_rate.sleep();
117  boost::asio::io_service io_service;
118  udp::resolver resolver(io_service);
119  udp::endpoint receiver_endpoint(udp::v4(), port);
120 
121  udp::socket socket(io_service);
122  socket.open(udp::v4());
123 
124  std::vector<uint8_t> cvec = {0, 1, 2, 3, 4};
125  auto buf = boost::asio::buffer(cvec);
126  // 2回送信
127  socket.send_to(buf, receiver_endpoint);
128  socket.send_to(buf, receiver_endpoint);
129  });
130 
131  // データの受け渡しが完了するまでspinする
132  ros::Rate loop_rate(100);
133  while (!ros::isShuttingDown() && !is_received) {
134  ros::spinOnce();
135  loop_rate.sleep();
136  }
137 
138  // 受信スレッドの停止
139  source->Stop();
140 
141  sending_thread.join();
142 
143  // 送信データはindexとvalueが一致した数列
144  for (int i = 0; i < received_vec.size(); i++) {
145  ASSERT_EQ(received_vec[i], i);
146  }
147 }
148 
149 // UDPでデータを受信したらcallbackが発火する部分のテスト
150 // 実際に利用する際にはunordered_mapに入れて使うので、入れた状態でテストする
151 TEST(TestSuite, socket_callback_in_map) {
152  ros::NodeHandle nh;
153 
154  // callbackが発火したことを示すflag
155  bool is_received = false;
156  // 最終的に評価に使う、受信データを格納するvector
157  std::vector<uint8_t> received_vec;
158 
159  // socketに渡すcallback
160  auto func_ptr = std::make_shared<std::function<void(std::vector<uint8_t>)>>(
161  [&](std::vector<uint8_t> vec) {
162  // 受信データを格納し、フラグを立てる
163  copy(vec.begin(), vec.end(), back_inserter(received_vec));
164  is_received = true;
165  });
166 
167  // objectを作成し、source objectをmapで管理
168  // 受信スレッドを開始
169  Injector<SocketFactory> injector(getUdpSocketComponent);
170  SocketFactory socketFactory(injector);
171  // データは送信しないのでportは何でも良い
172  auto source = socketFactory(udp::endpoint(udp::v4(), 0), func_ptr);
173  std::unordered_map<std::string, std::unique_ptr<Socket>> map;
174  map.emplace("socket", std::move(source));
175  map.at("socket")->Start();
176 
177  // 受信スレッドに対してデータを送信
178  unsigned short port = map.at("socket")->Port();
179  std::thread sending_thread([&] {
180  ros::Rate wait_rate(10);
181  wait_rate.sleep();
182  boost::asio::io_service io_service;
183  udp::resolver resolver(io_service);
184  udp::endpoint receiver_endpoint(udp::v4(), port);
185 
186  udp::socket socket(io_service);
187  socket.open(udp::v4());
188 
189  std::vector<uint8_t> cvec = {0, 1, 2, 3, 4};
190  auto buf = boost::asio::buffer(cvec);
191  socket.send_to(buf, receiver_endpoint);
192  });
193 
194  // データの受け渡しが完了するまでspinする
195  ros::Rate loop_rate(100);
196  while (!ros::isShuttingDown() && !is_received) {
197  ros::spinOnce();
198  loop_rate.sleep();
199  }
200 
201  // 受信スレッドの停止
202  map.at("socket")->Stop();
203 
204  sending_thread.join();
205 
206  // 送信データはindexとvalueが一致した数列
207  for (int i = 0; i < received_vec.size(); i++) {
208  ASSERT_EQ(received_vec[i], i);
209  }
210 }
211 
212 // 外部から受信したデータの送信
213 TEST(TestSuite, socket_send_data) {
214  ros::NodeHandle nh;
215 
216  // callbackが発火したことを示すflag
217  bool is_received = false;
218  // 最終的に評価に使う、受信データを格納するvector
219  std::vector<uint8_t> received_vec;
220 
221  // 受信socketをrandomなポート番号でbind
222  boost::asio::io_service io_service;
223  udp::socket socket(io_service, udp::endpoint(udp::v4(), 0));
224  // 受信用ポートの情報を取得
225  auto endpoint = socket.local_endpoint();
226  // 受信スレッド開始
227  std::thread receiving_thread([&] {
228  boost::array<uint8_t, 2048> recv_buf;
229  udp::endpoint remote_endpoint;
230  boost::system::error_code error;
231  size_t len = socket.receive_from(boost::asio::buffer(recv_buf),
232  remote_endpoint, 0, error);
233  received_vec.clear();
234  received_vec.insert(received_vec.end(), &recv_buf[0], &recv_buf[len]);
235 
236  is_received = true;
237  });
238 
239  // 受信スレッド開始完了するまで待機
240  // 100ms程度待てば十分
241  ros::Rate loop_rate(100);
242  loop_rate.sleep();
243 
244  // socketに渡すcallback
245  // このテストでは呼ばれない
246  auto func_ptr = std::make_shared<std::function<void(std::vector<uint8_t>)>>(
247  [&](std::vector<uint8_t> vec) { ASSERT_TRUE(false); });
248 
249  // objectを作成し、受信スレッドを開始
250  Injector<SocketFactory> injector(getUdpSocketComponent);
251  SocketFactory socketFactory(injector);
252  // 受信スレッドのportを与える
253  auto source = socketFactory(endpoint, func_ptr);
254  source->Start();
255  std::vector<uint8_t> data{0, 1, 2, 3};
256  source->SendData(data);
257 
258  // 非同期実行なので、データが確実に届くまで待機が必要
259  loop_rate.sleep();
260  source->Stop();
261 
262  receiving_thread.join();
263 
264  // 送信データはindexとvalueが一致した数列
265  for (int i = 0; i < received_vec.size(); i++) {
266  ASSERT_EQ(received_vec[i], i);
267  }
268 
269  ASSERT_TRUE(is_received);
270 }
271 
272 // 外部から受信したデータの送信
273 // 実際に利用する際にはunordered_mapに入れて使うので、入れた状態でテストする
274 TEST(TestSuite, socket_send_data_in_map) {
275  ros::NodeHandle nh;
276 
277  // callbackが発火したことを示すflag
278  bool is_received = false;
279  // 最終的に評価に使う、受信データを格納するvector
280  std::vector<uint8_t> received_vec;
281 
282  // 受信socketをrandomなポート番号でbind
283  boost::asio::io_service io_service;
284  udp::socket socket(io_service, udp::endpoint(udp::v4(), 0));
285  // 受信用ポートの情報を取得
286  auto endpoint = socket.local_endpoint();
287  // 受信スレッド開始
288  std::thread receiving_thread([&] {
289  boost::array<uint8_t, 2048> recv_buf;
290  udp::endpoint remote_endpoint;
291  boost::system::error_code error;
292  size_t len = socket.receive_from(boost::asio::buffer(recv_buf),
293  remote_endpoint, 0, error);
294  received_vec.clear();
295  received_vec.insert(received_vec.end(), &recv_buf[0], &recv_buf[len]);
296 
297  is_received = true;
298  });
299 
300  // 受信スレッド開始完了するまで待機
301  // 100ms程度待てば十分
302  ros::Rate loop_rate(100);
303  loop_rate.sleep();
304 
305  // socketに渡すcallback
306  // このテストでは呼ばれない
307  auto func_ptr = std::make_shared<std::function<void(std::vector<uint8_t>)>>(
308  [&](std::vector<uint8_t> vec) { ASSERT_TRUE(false); });
309 
310  // objectを作成し、受信スレッドを開始
311  Injector<SocketFactory> injector(getUdpSocketComponent);
312  SocketFactory socketFactory(injector);
313  // 受信スレッドのportを与える
314  auto source = socketFactory(endpoint, func_ptr);
315  std::unordered_map<std::string, std::unique_ptr<Socket>> map;
316  map.emplace("socket", std::move(source));
317  map.at("socket")->Start();
318  std::vector<uint8_t> data{0, 1, 2, 3};
319  map.at("socket")->SendData(data);
320 
321  // 非同期実行なので、データが確実に届くまで待機が必要
322  loop_rate.sleep();
323  map.at("socket")->Stop();
324 
325  receiving_thread.join();
326 
327  // 送信データはindexとvalueが一致した数列
328  for (int i = 0; i < received_vec.size(); i++) {
329  ASSERT_EQ(received_vec[i], i);
330  }
331 
332  ASSERT_TRUE(is_received);
333 }
std::function< std::unique_ptr< Socket >(udp::endpoint, std::shared_ptr< std::function< void(std::vector< uint8_t >)> >)> SocketFactory
Definition: udp_socket.h:69
TEST(TestSuite, socket_callback)
ROSCPP_DECL bool isShuttingDown()
Component< SocketFactory > getUdpSocketComponent()
Definition: udp_socket.cpp:87
bool sleep()
ROSCPP_DECL void spinOnce()


skyway
Author(s): Toshiya Nakakura
autogenerated on Sat Apr 15 2023 02:08:21