service_client.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #include <gtest/gtest.h>
9 #include <uavcan/protocol/RestartNode.hpp>
10 #include <uavcan/protocol/GetDataTypeInfo.hpp>
11 #include <root_ns_a/StringService.hpp>
12 #include <root_ns_a/EmptyService.hpp>
13 #include <queue>
14 #include <sstream>
15 #include "test_node.hpp"
16 
17 
18 template <typename DataType>
20 {
24  typename DataType::Response last_response;
25  std::queue<typename DataType::Response> responses;
26 
28  {
29  std::cout << result << std::endl;
30  last_status = result.getStatus();
31  last_response = result.getResponse();
32  last_server_node_id = result.getCallID().server_node_id;
33  responses.push(result.getResponse());
34  }
35 
36  bool match(StatusType status, uavcan::NodeID server_node_id, const typename DataType::Response& response) const
37  {
38  if (status == last_status &&
39  server_node_id == last_server_node_id &&
41  {
42  return true;
43  }
44  else
45  {
46  std::cout << "MISMATCH: status=" << int(last_status) << ", last_server_node_id="
47  << int(last_server_node_id.get()) << ", last response:\n" << last_response << std::endl;
48  return false;
49  }
50  }
51 
54 
56 };
57 
58 
61 {
62  rsp.string_response = "Request string: ";
63  rsp.string_response += req.string_request;
64 }
65 
69 {
70  rsp.string_response = "Request string: ";
71  rsp.string_response += req.string_request;
72  ASSERT_TRUE(rsp.isResponseEnabled());
73  rsp.setResponseEnabled(false);
74  ASSERT_FALSE(rsp.isResponseEnabled());
75 }
76 
79 {
80  // Nothing to do - the service is empty
81 }
82 
83 
84 TEST(ServiceClient, Basic)
85 {
87 
88  // Type registration
91 
92  // Server
94  ASSERT_EQ(0, server.start(stringServiceServerCallback));
95 
96  {
97  // Caller
99  typedef uavcan::ServiceClient<root_ns_a::StringService,
102 
103  ClientType client1(nodes.b);
104  ClientType client2(nodes.b);
105  ClientType client3(nodes.b);
106 
107  ASSERT_EQ(0, client1.getNumPendingCalls());
108  ASSERT_EQ(0, client2.getNumPendingCalls());
109  ASSERT_EQ(0, client3.getNumPendingCalls());
110 
111  ASSERT_FALSE(client1.hasPendingCallToServer(1));
112 
113  client1.setCallback(handler.bind());
114  client2.setCallback(client1.getCallback());
115  client3.setCallback(client1.getCallback());
116  client3.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));
117 
118  ASSERT_EQ(1, nodes.a.getDispatcher().getNumServiceRequestListeners());
119  ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // NOT listening!
120 
121  root_ns_a::StringService::Request request;
122  request.string_request = "Hello world";
123 
124  std::cout << "!!! Calling!" << std::endl;
125 
126  ASSERT_LT(0, client1.call(1, request)); // OK
127  ASSERT_LT(0, client1.call(1, request)); // OK - second request
128  ASSERT_LT(0, client2.call(1, request)); // OK
129  ASSERT_LT(0, client3.call(99, request)); // Will timeout!
130  ASSERT_LT(0, client3.call(1, request)); // OK - second request
131 
132  ASSERT_TRUE(client1.hasPendingCallToServer(1));
133  ASSERT_TRUE(client2.hasPendingCallToServer(1));
134  ASSERT_TRUE(client3.hasPendingCallToServer(99));
135  ASSERT_TRUE(client3.hasPendingCallToServer(1));
136 
137  std::cout << "!!! Spinning!" << std::endl;
138 
139  ASSERT_EQ(3, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Listening now!
140 
141  ASSERT_TRUE(client1.hasPendingCalls());
142  ASSERT_TRUE(client2.hasPendingCalls());
143  ASSERT_TRUE(client3.hasPendingCalls());
144 
145  ASSERT_EQ(2, client1.getNumPendingCalls());
146  ASSERT_EQ(1, client2.getNumPendingCalls());
147  ASSERT_EQ(2, client3.getNumPendingCalls());
148 
149  ASSERT_EQ(uavcan::NodeID(1), client2.getCallIDByIndex(0).server_node_id);
150  ASSERT_EQ(uavcan::NodeID(), client2.getCallIDByIndex(1).server_node_id);
151 
153 
154  std::cout << "!!! Spin finished!" << std::endl;
155 
156  ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Third is still listening!
157 
158  ASSERT_FALSE(client1.hasPendingCalls());
159  ASSERT_FALSE(client2.hasPendingCalls());
160  ASSERT_TRUE(client3.hasPendingCalls());
161 
162  ASSERT_EQ(0, client1.getNumPendingCalls());
163  ASSERT_EQ(0, client2.getNumPendingCalls());
164  ASSERT_EQ(1, client3.getNumPendingCalls()); // The one addressed to 99 is still waiting
165 
166  // Validating
167  root_ns_a::StringService::Response expected_response;
168  expected_response.string_response = "Request string: Hello world";
169  ASSERT_TRUE(handler.match(ResultType::Success, 1, expected_response));
170 
172 
173  ASSERT_FALSE(client1.hasPendingCalls());
174  ASSERT_FALSE(client2.hasPendingCalls());
175  ASSERT_FALSE(client3.hasPendingCalls());
176 
177  ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Third has timed out :(
178 
179  // Validating
180  ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 99, root_ns_a::StringService::Response()));
181 
182  // Stray request
183  ASSERT_LT(0, client3.call(99, request)); // Will timeout!
184  ASSERT_TRUE(client3.hasPendingCalls());
185  ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());
186  }
187 
188  // All destroyed - nobody listening
189  ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners());
190 }
191 
192 
193 TEST(ServiceClient, Rejection)
194 {
196 
197  // Type registration
200 
201  // Server
203  ASSERT_EQ(0, server.start(rejectingStringServiceServerCallback));
204 
205  // Caller
207  typedef uavcan::ServiceClient<root_ns_a::StringService,
210 
211  ClientType client1(nodes.b);
212  client1.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));
213  client1.setCallback(handler.bind());
214 
215  root_ns_a::StringService::Request request;
216  request.string_request = "Hello world";
217 
218  ASSERT_LT(0, client1.call(1, request));
219 
220  ASSERT_EQ(uavcan::NodeID(1), client1.getCallIDByIndex(0).server_node_id);
221  ASSERT_EQ(uavcan::NodeID(), client1.getCallIDByIndex(1).server_node_id);
222 
223  ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());
224  ASSERT_TRUE(client1.hasPendingCalls());
225  ASSERT_TRUE(client1.hasPendingCallToServer(1));
226 
228  ASSERT_FALSE(client1.hasPendingCalls());
229  ASSERT_FALSE(client1.hasPendingCallToServer(1));
230 
231  ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Timed out
232 
233  ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 1, root_ns_a::StringService::Response()));
234 }
235 
236 
237 TEST(ServiceClient, ConcurrentCalls)
238 {
240 
241  // Type registration
244 
245  // Server
247  ASSERT_EQ(0, server.start(stringServiceServerCallback));
248 
249  // Caller
251  typedef uavcan::ServiceClient<root_ns_a::StringService,
254 
255  /*
256  * Initializing
257  */
258  ClientType client(nodes.b);
259 
260  ASSERT_EQ(0, client.getNumPendingCalls());
261 
262  client.setCallback(handler.bind());
263 
264  ASSERT_EQ(1, nodes.a.getDispatcher().getNumServiceRequestListeners());
265  ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // NOT listening!
266 
267  ASSERT_FALSE(client.hasPendingCalls());
268  ASSERT_EQ(0, client.getNumPendingCalls());
269 
270  /*
271  * Calling ten requests, the last one will be cancelled
272  * Note that there will be non-unique transfer ID values; the client must handle that correctly
273  */
274  uavcan::ServiceCallID last_call_id;
275  for (int i = 0; i < 10; i++)
276  {
277  std::ostringstream os;
278  os << i;
279  root_ns_a::StringService::Request request;
280  request.string_request = os.str().c_str();
281  ASSERT_LT(0, client.call(1, request, last_call_id));
282  }
283 
284  ASSERT_LT(0, client.call(99, root_ns_a::StringService::Request())); // Will timeout in 1000 ms
285 
286  client.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));
287 
288  ASSERT_LT(0, client.call(88, root_ns_a::StringService::Request())); // Will timeout in 100 ms
289 
290  ASSERT_TRUE(client.hasPendingCalls());
291  ASSERT_EQ(12, client.getNumPendingCalls());
292 
293  ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Listening
294 
295  /*
296  * Cancelling one
297  */
298  client.cancelCall(last_call_id);
299 
300  ASSERT_TRUE(client.hasPendingCalls());
301  ASSERT_EQ(11, client.getNumPendingCalls());
302 
303  ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Still listening
304 
305  /*
306  * Spinning
307  */
309 
310  ASSERT_TRUE(client.hasPendingCalls());
311  ASSERT_EQ(2, client.getNumPendingCalls()); // Two still pending
312  ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Still listening
313 
314  /*
315  * Validating the ones that didn't timeout
316  */
317  root_ns_a::StringService::Response last_response;
318  for (int i = 0; i < 9; i++)
319  {
320  std::ostringstream os;
321  os << "Request string: " << i;
322  last_response.string_response = os.str().c_str();
323 
324  ASSERT_FALSE(handler.responses.empty());
325 
326  ASSERT_STREQ(last_response.string_response.c_str(), handler.responses.front().string_response.c_str());
327 
328  handler.responses.pop();
329  }
330 
331  ASSERT_TRUE(handler.responses.empty());
332 
333  /*
334  * Validating the 100 ms timeout
335  */
337 
338  ASSERT_TRUE(client.hasPendingCalls());
339  ASSERT_EQ(1, client.getNumPendingCalls()); // One dropped
340  ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Still listening
341 
342  ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 88, root_ns_a::StringService::Response()));
343 
344  /*
345  * Validating the 1000 ms timeout
346  */
348 
349  ASSERT_FALSE(client.hasPendingCalls());
350  ASSERT_EQ(0, client.getNumPendingCalls()); // All finished
351  ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Not listening
352 
353  ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 99, root_ns_a::StringService::Response()));
354 }
355 
356 
357 TEST(ServiceClient, Empty)
358 {
360 
361  // Type registration
364 
365  // Server
367  ASSERT_EQ(0, server.start(emptyServiceServerCallback));
368 
369  {
370  // Caller
371  typedef uavcan::ServiceClient<root_ns_a::EmptyService,
374 
375  ClientType client(nodes.b);
376 
377  client.setCallback(handler.bind());
378 
379  root_ns_a::EmptyService::Request request;
380 
381  ASSERT_LT(0, client.call(1, request)); // OK
382  }
383 
384  // All destroyed - nobody listening
385  ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners());
386 }
387 
388 
389 TEST(ServiceClient, Priority)
390 {
392 
393  // Type registration
396 
397  // Initializing
398  typedef uavcan::ServiceClient<root_ns_a::EmptyService,
401  ClientType client(nodes.b);
402  client.setCallback(handler.bind());
403 
404  // Calling
405  root_ns_a::EmptyService::Request request;
406 
407  client.setPriority(0);
408  ASSERT_LT(0, client.call(1, request)); // OK
409 
410  client.setPriority(10);
411  ASSERT_LT(0, client.call(1, request)); // OK
412 
413  client.setPriority(20);
414  ASSERT_LT(0, client.call(1, request)); // OK
415 
416  client.setPriority(31);
417  ASSERT_LT(0, client.call(1, request)); // OK
418 
419  // Validating
420  ASSERT_EQ(4, nodes.can_a.read_queue.size());
421 
423 
424  ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front()));
425  nodes.can_a.read_queue.pop();
426  ASSERT_EQ(0, frame.getPriority().get());
427 
428  ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front()));
429  nodes.can_a.read_queue.pop();
430  ASSERT_EQ(10, frame.getPriority().get());
431 
432  ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front()));
433  nodes.can_a.read_queue.pop();
434  ASSERT_EQ(20, frame.getPriority().get());
435 
436  ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front()));
437  nodes.can_a.read_queue.pop();
438  ASSERT_EQ(31, frame.getPriority().get());
439 }
440 
441 
442 TEST(ServiceClient, Sizes)
443 {
444  using namespace uavcan;
445 
446  std::cout << "GetDataTypeInfo server: " <<
447  sizeof(ServiceServer<protocol::GetDataTypeInfo>) << std::endl;
448 
449  std::cout << "RestartNode server: " <<
450  sizeof(ServiceServer<protocol::RestartNode>) << std::endl;
451 
452  std::cout << "GetDataTypeInfo client: " <<
453  sizeof(ServiceClient<protocol::GetDataTypeInfo>) << std::endl;
454 }
response
const std::string response
ServiceCallResultHandler::last_status
StatusType last_status
Definition: service_client.cpp:22
TEST
TEST(ServiceClient, Basic)
Definition: service_client.cpp:84
uavcan::DefaultDataTypeRegistrator
Definition: global_data_type_registry.hpp:186
rejectingStringServiceServerCallback
static void rejectingStringServiceServerCallback(const uavcan::ReceivedDataStructure< root_ns_a::StringService::Request > &req, uavcan::ServiceResponseDataStructure< root_ns_a::StringService::Response > &rsp)
Definition: service_client.cpp:66
uavcan::ServiceCallResult::getCallID
ServiceCallID getCallID() const
Definition: service_client.hpp:83
ServiceCallResultHandler::last_server_node_id
uavcan::NodeID last_server_node_id
Definition: service_client.cpp:23
uavcan::ServiceResponseDataStructure::isResponseEnabled
bool isResponseEnabled() const
Definition: service_server.hpp:61
uavcan::NodeID::get
uint8_t get() const
Definition: transfer.hpp:132
uavcan::NodeID
Definition: transfer.hpp:112
uavcan::DurationBase< MonotonicDuration >::fromMSec
static MonotonicDuration fromMSec(int64_t ms)
Definition: time.hpp:41
uavcan::Dispatcher::getNumServiceRequestListeners
unsigned getNumServiceRequestListeners() const
Definition: dispatcher.hpp:178
ServiceCallResultHandler::handleResponse
void handleResponse(const uavcan::ServiceCallResult< DataType > &result)
Definition: service_client.cpp:27
uavcan::INode::getDispatcher
Dispatcher & getDispatcher()
Definition: abstract_node.hpp:28
service_client.hpp
ServiceCallResultHandler
Definition: service_client.cpp:19
uavcan::ReceivedDataStructure
Definition: generic_subscriber.hpp:39
uavcan::ServiceCallResult
Definition: service_client.hpp:54
ServiceCallResultHandler::match
bool match(StatusType status, uavcan::NodeID server_node_id, const typename DataType::Response &response) const
Definition: service_client.cpp:36
uavcan::ServiceServer
Definition: service_server.hpp:90
ServiceCallResultHandler::last_response
DataType::Response last_response
Definition: service_client.cpp:24
uavcan::ServiceCallResult::getStatus
Status getStatus() const
Definition: service_client.hpp:81
uavcan::Dispatcher::getNumServiceResponseListeners
unsigned getNumServiceResponseListeners() const
Definition: dispatcher.hpp:179
InterlinkedTestNodes
Definition: test_node.hpp:149
method_binder.hpp
test_node.hpp
uavcan::ServiceClient
Definition: service_client.hpp:217
uavcan::ServiceCallResult::getResponse
const ResponseFieldType & getResponse() const
Definition: service_client.hpp:88
uavcan::ServiceServer::start
int start(const Callback &callback)
Definition: service_server.hpp:158
ServiceCallResultHandler::bind
Binder bind()
Definition: service_client.cpp:55
int
int
Definition: libstubs.cpp:120
frame
uavcan::CanFrame frame
Definition: can.cpp:78
uavcan::MethodBinder
Definition: method_binder.hpp:20
InterlinkedTestNodes::a
TestNode a
Definition: test_node.hpp:155
stringServiceServerCallback
static void stringServiceServerCallback(const uavcan::ReceivedDataStructure< root_ns_a::StringService::Request > &req, uavcan::ServiceResponseDataStructure< root_ns_a::StringService::Response > &rsp)
Definition: service_client.cpp:59
uavcan::Frame
Definition: frame.hpp:17
InterlinkedTestNodes::spinBoth
int spinBoth(uavcan::MonotonicDuration duration)
Definition: test_node.hpp:176
uavcan::ServiceCallID
Definition: service_client.hpp:27
uavcan::ServiceResponseDataStructure
Definition: service_server.hpp:40
ServiceCallResultHandler::responses
std::queue< typename DataType::Response > responses
Definition: service_client.cpp:25
PairableCanDriver::read_queue
std::queue< uavcan::CanFrame > read_queue
Definition: test_node.hpp:56
uavcan::ServiceResponseDataStructure::setResponseEnabled
void setResponseEnabled(bool x)
Definition: service_server.hpp:56
uavcan::GlobalDataTypeRegistry::instance
static GlobalDataTypeRegistry & instance()
Definition: uc_global_data_type_registry.cpp:128
ServiceCallResultHandler::Binder
uavcan::MethodBinder< ServiceCallResultHandler *, void(ServiceCallResultHandler::*)(const uavcan::ServiceCallResult< DataType > &)> Binder
Definition: service_client.cpp:53
uavcan
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:204
ServiceCallResultHandler::StatusType
uavcan::ServiceCallResult< DataType >::Status StatusType
Definition: service_client.cpp:21
InterlinkedTestNodes::b
TestNode b
Definition: test_node.hpp:156
uavcan::ServiceCallResult::Status
Status
Definition: service_client.hpp:59
service_server.hpp
emptyServiceServerCallback
static void emptyServiceServerCallback(const uavcan::ReceivedDataStructure< root_ns_a::EmptyService::Request > &, uavcan::ServiceResponseDataStructure< root_ns_a::EmptyService::Response > &)
Definition: service_client.cpp:77
InterlinkedTestNodes::can_a
PairableCanDriver can_a
Definition: test_node.hpp:153


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:03