message_test.cc
Go to the documentation of this file.
1 
37 #include <chrono>
38 #include <optional>
39 
40 #include <gtest/gtest.h>
41 
43 
45 
46 using namespace multisense::legacy;
47 
49 {
50  auto full_sequence_id = unwrap_sequence_id(0, -1, 0);
51 
52  EXPECT_EQ(full_sequence_id, 0);
53 
54  full_sequence_id = unwrap_sequence_id(0, 0, 0);
55 
56  EXPECT_EQ(full_sequence_id, 0);
57 }
58 
59 TEST(unwrap_sequence_id, no_increment)
60 {
61  const auto full_sequence_id = unwrap_sequence_id(1, 1, 0);
62 
63  EXPECT_EQ(full_sequence_id, 0);
64 }
65 
67 {
68  const auto full_sequence_id = unwrap_sequence_id(1, 0, 0);
69 
70  EXPECT_EQ(full_sequence_id, 1);
71 }
72 
74 {
75  const auto full_sequence_id = unwrap_sequence_id(0, 65535, 0);
76 
77  EXPECT_EQ(full_sequence_id, 1);
78 }
79 
80 TEST(unwrap_sequence_id, rollover_unique)
81 {
82  const auto full_sequence_id = unwrap_sequence_id(0, 65535, 123456);
83 
84  EXPECT_EQ(full_sequence_id, 123457);
85 }
86 
87 TEST(header_valid, invalid)
88 {
89  std::vector<uint8_t> data(50, 0);
90 
91  ASSERT_FALSE(header_valid(data));
92 }
93 
95 {
96  using namespace crl::multisense::details;
97 
98  wire::SysDeviceInfo info{};
99 
100  auto serialized = serialize(info, 10, 9000);
101 
102  ASSERT_TRUE(header_valid(serialized));
103 }
104 
106 {
107  using namespace crl::multisense::details;
108 
109  wire::SysDeviceInfo info{};
110 
111  auto serialized = serialize(info, 10, 9000);
112 
113  const auto type = get_message_type(serialized);
114 
115  ASSERT_EQ(type, wire::SysDeviceInfo::ID);
116 }
117 
119 {
120  const auto full_size = get_full_message_size({});
121 
122  ASSERT_FALSE(static_cast<bool>(full_size));
123 }
124 
126 {
127  using namespace crl::multisense::details;
128 
129  wire::SysDeviceInfo info{};
130 
131  const auto serialized = serialize(info, 10, 9000);
132 
133  const auto full_size = get_full_message_size(serialized);
134 
135  ASSERT_TRUE(static_cast<bool>(full_size));
136 
137  ASSERT_GT(full_size.value(), 20);
138  ASSERT_LT(full_size.value(), 200);
139 }
140 
141 TEST(serialize_deserialize, roundtrip)
142 {
143  using namespace crl::multisense::details;
144 
145  wire::SysDeviceInfo info{};
146  info.name = "test";
147  info.numberOfPcbs = 0;
148  info.motorName = "bar";
149 
150  auto serialized = serialize(info, 10, 9000);
151 
152  //
153  // Remove the wire::Header we added for the MultiSense
154  //
155  serialized.erase(std::begin(serialized), std::begin(serialized) + sizeof(wire::Header));
156 
157 
158  const auto round_trip = deserialize<wire::SysDeviceInfo>(serialized);
159 
160  ASSERT_EQ(round_trip.name, info.name);
161  ASSERT_EQ(round_trip.numberOfPcbs, info.numberOfPcbs);
162  ASSERT_EQ(round_trip.motorName, info.motorName);
163 }
164 
165 TEST(MessageAssembler, process_notify_wait_for)
166 {
167  using namespace crl::multisense::details;
168  using namespace std::chrono_literals;
169 
170  wire::SysDeviceInfo info{};
171  info.name = "test";
172  auto serialized = serialize(info, 10, 9000);
173 
174  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{10, 9000, 2, 100000})};
175  auto registration = assembler.register_message(wire::SysDeviceInfo::ID);
176  ASSERT_TRUE(assembler.process_packet(serialized));
177 
178  const auto output = registration->wait<wire::SysDeviceInfo>(std::make_optional(500ms));
179 
180  ASSERT_TRUE(static_cast<bool>(output));
181 
182  ASSERT_EQ(output->name, info.name);
183 }
184 
185 
186 TEST(MessageAssembler, process_notify_wait)
187 {
188  using namespace crl::multisense::details;
189  using namespace std::chrono_literals;
190 
191  wire::SysDeviceInfo info{};
192  info.name = "test_wait";
193  auto serialized = serialize(info, 10, 9000);
194 
195  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{10, 9000, 2, 100000})};
196  auto registration = assembler.register_message(wire::SysDeviceInfo::ID);
197  ASSERT_TRUE(assembler.process_packet(serialized));
198 
199  const auto output = registration->wait<wire::SysDeviceInfo>();
200 
201  ASSERT_TRUE(static_cast<bool>(output));
202 
203  ASSERT_EQ(output->name, info.name);
204 }
205 
206 TEST(MessageAssembler, process_notify_wait_for_multi_registrations)
207 {
208  using namespace crl::multisense::details;
209  using namespace std::chrono_literals;
210 
211  wire::SysDeviceInfo info{};
212  info.name = "test";
213  auto serialized = serialize(info, 10, 9000);
214 
215  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{10, 9000, 2, 100000})};
216  auto registration0 = assembler.register_message(wire::SysDeviceInfo::ID);
217  auto registration1 = assembler.register_message(wire::SysDeviceInfo::ID);
218  ASSERT_TRUE(assembler.process_packet(serialized));
219 
220  const auto output0 = registration0->wait<wire::SysDeviceInfo>(std::make_optional(500ms));
221  const auto output1 = registration1->wait<wire::SysDeviceInfo>(std::make_optional(500ms));
222 
223  ASSERT_TRUE(static_cast<bool>(output0));
224  ASSERT_TRUE(static_cast<bool>(output1));
225 
226  ASSERT_EQ(output0->name, info.name);
227  ASSERT_EQ(output1->name, info.name);
228 }
229 
230 TEST(MessageAssembler, process_notify_remove_registration)
231 {
232  using namespace crl::multisense::details;
233  using namespace std::chrono_literals;
234 
235  wire::SysDeviceInfo info{};
236  info.name = "test";
237  auto serialized = serialize(info, 10, 9000);
238 
239  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{10, 9000, 2, 100000})};
240  auto registration = assembler.register_message(wire::SysDeviceInfo::ID);
241  assembler.remove_registration(wire::SysDeviceInfo::ID);
242  ASSERT_TRUE(assembler.process_packet(serialized));
243 
244  //
245  // Since we don't have an active registration we should not get a valid message
246  //
247  const auto output = registration->wait<wire::SysDeviceInfo>(std::make_optional(500ms));
248 
249  ASSERT_FALSE(static_cast<bool>(output));
250 }
251 
252 TEST(MessageAssembler, process_callback)
253 {
254  using namespace crl::multisense::details;
255  using namespace std::chrono_literals;
256 
257  wire::SysDeviceInfo info{};
258  info.name = "test_callback";
259  auto serialized = serialize(info, 10, 9000);
260 
261  //
262  // Our lambda should be called when the packet is processed
263  //
264  wire::SysDeviceInfo output;
265  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{10, 9000, 2, 100000})};
266  assembler.register_callback(wire::SysDeviceInfo::ID,
267  [&output](const auto &data)
268  {
269  output = deserialize<wire::SysDeviceInfo>(*data);
270  });
271  ASSERT_TRUE(assembler.process_packet(serialized));
272 
273  ASSERT_EQ(output.name, info.name);
274 
275  //
276  // Remove our callback and make sure our output does not get updated
277  //
278  assembler.remove_callback(wire::SysDeviceInfo::ID);
279 
280  info.name = "test_callback_new";
281  serialized = serialize(info, 11, 9000);
282  ASSERT_TRUE(assembler.process_packet(serialized));
283 
284  ASSERT_NE(output.name, info.name);
285 }
286 
287 TEST(MessageAssembler, use_all_buffers)
288 {
289  using namespace crl::multisense::details;
290  using namespace std::chrono_literals;
291 
292  wire::SysDeviceInfo info{};
293  info.name = "test_callback";
294  auto serialized = serialize(info, 10, 9000);
295 
296  //
297  // Our lambda should be called when the packet is processed
298  //
299  std::vector<std::shared_ptr<const std::vector<uint8_t>>> outputs;
300  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{2, 9000, 1, 100000})};
301  assembler.register_callback(wire::SysDeviceInfo::ID,
302  [&outputs](const auto data)
303  {
304  outputs.push_back(data);
305  });
306  ASSERT_TRUE(assembler.process_packet(serialized));
307  ASSERT_TRUE(assembler.process_packet(serialized));
308 
309  //
310  // At this point we should be out of our small buffers
311  //
312  ASSERT_FALSE(assembler.process_packet(serialized));
313 }
314 
315 TEST(MessageAssembler, invalid_message)
316 {
317  using namespace crl::multisense::details;
318  using namespace std::chrono_literals;
319 
320  wire::SysDeviceInfo info{};
321  info.name = "test_callback";
322  auto serialized = serialize(info, 10, 9000);
323 
324  //
325  // Mess up our message
326  //
327  serialized[0] = 123;
328 
329  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{2, 9000, 1, 100000})};
330 
331  //
332  // Processing should return false
333  //
334  ASSERT_FALSE(assembler.process_packet(serialized));
335  ASSERT_FALSE(assembler.process_packet(std::vector<uint8_t>{}));
336 }
337 
338 TEST(MessageAssembler, only_large_buffers)
339 {
340  using namespace crl::multisense::details;
341  using namespace std::chrono_literals;
342 
343  wire::SysDeviceInfo info{};
344  info.name = "test_callback";
345  auto serialized = serialize(info, 10, 9000);
346 
347  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{1, 1, 1, 100000})};
348  auto registration = assembler.register_message(wire::SysDeviceInfo::ID);
349 
350  ASSERT_TRUE(assembler.process_packet(serialized));
351 
352  const auto output = registration->wait<wire::SysDeviceInfo>(std::make_optional(500ms));
353 
354  ASSERT_TRUE(static_cast<bool>(output));
355 
356  ASSERT_EQ(output->name, info.name);
357 }
358 
359 TEST(MessageAssembler, multi_large_packets)
360 {
361  using namespace crl::multisense::details;
362  using namespace std::chrono_literals;
363 
364  wire::SysDeviceInfo info{};
365  info.name = "test_callback";
366  auto serialized = serialize(info, 0, 9000);
367 
368  //
369  // Update our message size to indicate our message is huge
370  //
371  auto sequence_id = reinterpret_cast<uint16_t*>(&serialized[8]);
372  auto message_length = reinterpret_cast<uint32_t*>(&serialized[10]);
373  *message_length = 10000;
374 
375  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{1, 1, 1, 100000})};
376  auto registration = assembler.register_message(wire::SysDeviceInfo::ID);
377 
378  //
379  // We should be able to process the message, but we wont get a valid message since we messed with
380  // the message length. We should be internally dropping all these messages when a message with the
381  // next sequence id shows up
382  //
383  for (size_t i = 1 ; i < 100 ; ++i)
384  {
385  ASSERT_TRUE(assembler.process_packet(serialized));
386  {
387  const auto output = registration->wait<wire::SysDeviceInfo>(std::make_optional(1us));
388  ASSERT_FALSE(static_cast<bool>(output));
389  }
390 
391  *sequence_id = i;
392  }
393 }
394 
395 TEST(MessageAssembler, stats_valid_message)
396 {
397  using namespace crl::multisense::details;
398  using namespace std::chrono_literals;
399 
400  wire::SysDeviceInfo info{};
401  info.name = "test_callback";
402  auto serialized = serialize(info, 10, 9000);
403 
404  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{2, 9000, 1, 100000})};
405 
406  ASSERT_TRUE(assembler.process_packet(serialized));
407 
408  const auto stats = assembler.get_message_statistics();
409 
410  ASSERT_EQ(stats.received_messages, 1);
411  ASSERT_EQ(stats.dropped_messages, 0);
412  ASSERT_EQ(stats.invalid_packets, 0);
413 }
414 
415 TEST(MessageAssembler, stats_invalid_message)
416 {
417  using namespace crl::multisense::details;
418  using namespace std::chrono_literals;
419 
420  wire::SysDeviceInfo info{};
421  info.name = "test_callback";
422  auto serialized = serialize(info, 10, 9000);
423 
424  //
425  // Mess up our message
426  //
427  serialized[0] = 123;
428 
429  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{2, 9000, 1, 100000})};
430 
431  //
432  // Processing should return false
433  //
434  ASSERT_FALSE(assembler.process_packet(serialized));
435  ASSERT_FALSE(assembler.process_packet(std::vector<uint8_t>{}));
436 
437  const auto stats = assembler.get_message_statistics();
438 
439  ASSERT_EQ(stats.received_messages, 0);
440  ASSERT_EQ(stats.dropped_messages, 0);
441  ASSERT_EQ(stats.invalid_packets, 2);
442 }
443 
444 TEST(MessageAssembler, stats_dropped_valid_message)
445 {
446  using namespace crl::multisense::details;
447  using namespace std::chrono_literals;
448 
449  wire::SysDeviceInfo info{};
450  info.name = "test_callback";
451  auto serialized = serialize(info, 10, 9000);
452 
453  MessageAssembler assembler{std::make_shared<BufferPool>(BufferPoolConfig{2, 9000, 1, 100000})};
454 
455  //
456  // Send in 3 messages. One valid, one of a very large size, one valid
457  //
458  ASSERT_TRUE(assembler.process_packet(serialized));
459 
460  serialized = serialize(info, 11, 9000);
461  wire::Header& header = *(reinterpret_cast<wire::Header*>(serialized.data()));
462  header.messageLength = 100000;
463  ASSERT_TRUE(assembler.process_packet(serialized));
464 
465  serialized = serialize(info, 12, 9000);
466  ASSERT_TRUE(assembler.process_packet(serialized));
467 
468  const auto stats = assembler.get_message_statistics();
469 
470  ASSERT_EQ(stats.received_messages, 2);
471  ASSERT_EQ(stats.dropped_messages, 1);
472  ASSERT_EQ(stats.invalid_packets, 0);
473 }
crl::multisense::details
Definition: Legacy/details/channel.cc:63
TEST
TEST(unwrap_sequence_id, null)
Definition: message_test.cc:48
multisense::legacy
Definition: calibration.cc:40
multisense::legacy::MessageAssembler
Process incoming network data, and try the data into valid MultiSense Wire messages.
Definition: message.hh:224
message.hh
device_info_utility.type
type
Definition: device_info_utility.py:61
multisense::legacy::unwrap_sequence_id
int64_t unwrap_sequence_id(uint16_t current_wire_id, int32_t previous_wire_id, int64_t current_sequence_id)
Unwrap a 16-bit wire sequence ID into a unique 64-bit local ID.
Definition: message.cc:54
multisense::legacy::serialize
std::vector< uint8_t > serialize(const T &message, uint16_t sequence_id, size_t mtu)
Serialize a MultiSense Wire message for transmission. This adds the wire header to the message for tr...
Definition: message.hh:103
multisense::legacy::MessageAssembler::register_callback
void register_callback(const crl::multisense::details::wire::IdType &message_id, std::function< void(std::shared_ptr< const std::vector< uint8_t >>)> callback)
Register a callback to receive valid messages of a given id. Note currently only one callback can be ...
Definition: message.cc:322
crl::multisense::details::wire::SysDeviceInfo
Definition: SysDeviceInfoMessage.hh:69
multisense::legacy::MessageAssembler::register_message
std::shared_ptr< MessageCondition > register_message(const crl::multisense::details::wire::IdType &message_id)
Register to be notified when a message of a given id arrives. Note this registration will only receiv...
Definition: message.cc:292
crl::multisense::details::wire::SysDeviceInfo::name
std::string name
Definition: SysDeviceInfoMessage.hh:135
multisense::legacy::get_full_message_size
std::optional< uint32_t > get_full_message_size(const std::vector< uint8_t > &raw_data)
Get the size of the full message in bytes from a raw data buffer.
Definition: message.cc:140
multisense::legacy::header_valid
bool header_valid(const std::vector< uint8_t > &raw_data)
Validate the Multisense header.
Definition: message.cc:96
multisense::legacy::BufferPoolConfig
Definition: LibMultiSense/include/details/legacy/storage.hh:46
header
std_msgs::Header const * header(const M &m)
multisense::legacy::get_message_type
crl::multisense::details::wire::IdType get_message_type(const std::vector< uint8_t > &raw_buffer)
Get the message type of the message from the buffer over the wire. Note this does account for the wir...
Definition: message.cc:128
SysDeviceInfoMessage.hh


multisense_lib
Author(s):
autogenerated on Thu Apr 17 2025 02:49:09