service_client.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /*
  2. * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #include <gtest/gtest.h>
  5. #include <uavcan/node/service_client.hpp>
  6. #include <uavcan/node/service_server.hpp>
  7. #include <uavcan/util/method_binder.hpp>
  8. #include <uavcan/protocol/RestartNode.hpp>
  9. #include <uavcan/protocol/GetDataTypeInfo.hpp>
  10. #include <root_ns_a/StringService.hpp>
  11. #include <root_ns_a/EmptyService.hpp>
  12. #include <queue>
  13. #include <sstream>
  14. #include "test_node.hpp"
  15. template <typename DataType>
  16. struct ServiceCallResultHandler
  17. {
  18. typedef typename uavcan::ServiceCallResult<DataType>::Status StatusType;
  19. StatusType last_status;
  20. uavcan::NodeID last_server_node_id;
  21. typename DataType::Response last_response;
  22. std::queue<typename DataType::Response> responses;
  23. void handleResponse(const uavcan::ServiceCallResult<DataType>& result)
  24. {
  25. std::cout << result << std::endl;
  26. last_status = result.getStatus();
  27. last_response = result.getResponse();
  28. last_server_node_id = result.getCallID().server_node_id;
  29. responses.push(result.getResponse());
  30. }
  31. bool match(StatusType status, uavcan::NodeID server_node_id, const typename DataType::Response& response) const
  32. {
  33. if (status == last_status &&
  34. server_node_id == last_server_node_id &&
  35. response == last_response)
  36. {
  37. return true;
  38. }
  39. else
  40. {
  41. std::cout << "MISMATCH: status=" << int(last_status) << ", last_server_node_id="
  42. << int(last_server_node_id.get()) << ", last response:\n" << last_response << std::endl;
  43. return false;
  44. }
  45. }
  46. typedef uavcan::MethodBinder<ServiceCallResultHandler*,
  47. void (ServiceCallResultHandler::*)(const uavcan::ServiceCallResult<DataType>&)> Binder;
  48. Binder bind() { return Binder(this, &ServiceCallResultHandler::handleResponse); }
  49. };
  50. static void stringServiceServerCallback(const uavcan::ReceivedDataStructure<root_ns_a::StringService::Request>& req,
  51. uavcan::ServiceResponseDataStructure<root_ns_a::StringService::Response>& rsp)
  52. {
  53. rsp.string_response = "Request string: ";
  54. rsp.string_response += req.string_request;
  55. }
  56. static void rejectingStringServiceServerCallback(
  57. const uavcan::ReceivedDataStructure<root_ns_a::StringService::Request>& req,
  58. uavcan::ServiceResponseDataStructure<root_ns_a::StringService::Response>& rsp)
  59. {
  60. rsp.string_response = "Request string: ";
  61. rsp.string_response += req.string_request;
  62. ASSERT_TRUE(rsp.isResponseEnabled());
  63. rsp.setResponseEnabled(false);
  64. ASSERT_FALSE(rsp.isResponseEnabled());
  65. }
  66. static void emptyServiceServerCallback(const uavcan::ReceivedDataStructure<root_ns_a::EmptyService::Request>&,
  67. uavcan::ServiceResponseDataStructure<root_ns_a::EmptyService::Response>&)
  68. {
  69. // Nothing to do - the service is empty
  70. }
  71. TEST(ServiceClient, Basic)
  72. {
  73. InterlinkedTestNodesWithSysClock nodes;
  74. // Type registration
  75. uavcan::GlobalDataTypeRegistry::instance().reset();
  76. uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator;
  77. // Server
  78. uavcan::ServiceServer<root_ns_a::StringService> server(nodes.a);
  79. ASSERT_EQ(0, server.start(stringServiceServerCallback));
  80. {
  81. // Caller
  82. typedef uavcan::ServiceCallResult<root_ns_a::StringService> ResultType;
  83. typedef uavcan::ServiceClient<root_ns_a::StringService,
  84. typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType;
  85. ServiceCallResultHandler<root_ns_a::StringService> handler;
  86. ClientType client1(nodes.b);
  87. ClientType client2(nodes.b);
  88. ClientType client3(nodes.b);
  89. ASSERT_EQ(0, client1.getNumPendingCalls());
  90. ASSERT_EQ(0, client2.getNumPendingCalls());
  91. ASSERT_EQ(0, client3.getNumPendingCalls());
  92. ASSERT_FALSE(client1.hasPendingCallToServer(1));
  93. client1.setCallback(handler.bind());
  94. client2.setCallback(client1.getCallback());
  95. client3.setCallback(client1.getCallback());
  96. client3.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));
  97. ASSERT_EQ(1, nodes.a.getDispatcher().getNumServiceRequestListeners());
  98. ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // NOT listening!
  99. root_ns_a::StringService::Request request;
  100. request.string_request = "Hello world";
  101. std::cout << "!!! Calling!" << std::endl;
  102. ASSERT_LT(0, client1.call(1, request)); // OK
  103. ASSERT_LT(0, client1.call(1, request)); // OK - second request
  104. ASSERT_LT(0, client2.call(1, request)); // OK
  105. ASSERT_LT(0, client3.call(99, request)); // Will timeout!
  106. ASSERT_LT(0, client3.call(1, request)); // OK - second request
  107. ASSERT_TRUE(client1.hasPendingCallToServer(1));
  108. ASSERT_TRUE(client2.hasPendingCallToServer(1));
  109. ASSERT_TRUE(client3.hasPendingCallToServer(99));
  110. ASSERT_TRUE(client3.hasPendingCallToServer(1));
  111. std::cout << "!!! Spinning!" << std::endl;
  112. ASSERT_EQ(3, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Listening now!
  113. ASSERT_TRUE(client1.hasPendingCalls());
  114. ASSERT_TRUE(client2.hasPendingCalls());
  115. ASSERT_TRUE(client3.hasPendingCalls());
  116. ASSERT_EQ(2, client1.getNumPendingCalls());
  117. ASSERT_EQ(1, client2.getNumPendingCalls());
  118. ASSERT_EQ(2, client3.getNumPendingCalls());
  119. ASSERT_EQ(uavcan::NodeID(1), client2.getCallIDByIndex(0).server_node_id);
  120. ASSERT_EQ(uavcan::NodeID(), client2.getCallIDByIndex(1).server_node_id);
  121. nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(20));
  122. std::cout << "!!! Spin finished!" << std::endl;
  123. ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Third is still listening!
  124. ASSERT_FALSE(client1.hasPendingCalls());
  125. ASSERT_FALSE(client2.hasPendingCalls());
  126. ASSERT_TRUE(client3.hasPendingCalls());
  127. ASSERT_EQ(0, client1.getNumPendingCalls());
  128. ASSERT_EQ(0, client2.getNumPendingCalls());
  129. ASSERT_EQ(1, client3.getNumPendingCalls()); // The one addressed to 99 is still waiting
  130. // Validating
  131. root_ns_a::StringService::Response expected_response;
  132. expected_response.string_response = "Request string: Hello world";
  133. ASSERT_TRUE(handler.match(ResultType::Success, 1, expected_response));
  134. nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(200));
  135. ASSERT_FALSE(client1.hasPendingCalls());
  136. ASSERT_FALSE(client2.hasPendingCalls());
  137. ASSERT_FALSE(client3.hasPendingCalls());
  138. ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Third has timed out :(
  139. // Validating
  140. ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 99, root_ns_a::StringService::Response()));
  141. // Stray request
  142. ASSERT_LT(0, client3.call(99, request)); // Will timeout!
  143. ASSERT_TRUE(client3.hasPendingCalls());
  144. ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());
  145. }
  146. // All destroyed - nobody listening
  147. ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners());
  148. }
  149. TEST(ServiceClient, Rejection)
  150. {
  151. InterlinkedTestNodesWithSysClock nodes;
  152. // Type registration
  153. uavcan::GlobalDataTypeRegistry::instance().reset();
  154. uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator;
  155. // Server
  156. uavcan::ServiceServer<root_ns_a::StringService> server(nodes.a);
  157. ASSERT_EQ(0, server.start(rejectingStringServiceServerCallback));
  158. // Caller
  159. typedef uavcan::ServiceCallResult<root_ns_a::StringService> ResultType;
  160. typedef uavcan::ServiceClient<root_ns_a::StringService,
  161. typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType;
  162. ServiceCallResultHandler<root_ns_a::StringService> handler;
  163. ClientType client1(nodes.b);
  164. client1.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));
  165. client1.setCallback(handler.bind());
  166. root_ns_a::StringService::Request request;
  167. request.string_request = "Hello world";
  168. ASSERT_LT(0, client1.call(1, request));
  169. ASSERT_EQ(uavcan::NodeID(1), client1.getCallIDByIndex(0).server_node_id);
  170. ASSERT_EQ(uavcan::NodeID(), client1.getCallIDByIndex(1).server_node_id);
  171. ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());
  172. ASSERT_TRUE(client1.hasPendingCalls());
  173. ASSERT_TRUE(client1.hasPendingCallToServer(1));
  174. nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(200));
  175. ASSERT_FALSE(client1.hasPendingCalls());
  176. ASSERT_FALSE(client1.hasPendingCallToServer(1));
  177. ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Timed out
  178. ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 1, root_ns_a::StringService::Response()));
  179. }
  180. TEST(ServiceClient, ConcurrentCalls)
  181. {
  182. InterlinkedTestNodesWithSysClock nodes;
  183. // Type registration
  184. uavcan::GlobalDataTypeRegistry::instance().reset();
  185. uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator;
  186. // Server
  187. uavcan::ServiceServer<root_ns_a::StringService> server(nodes.a);
  188. ASSERT_EQ(0, server.start(stringServiceServerCallback));
  189. // Caller
  190. typedef uavcan::ServiceCallResult<root_ns_a::StringService> ResultType;
  191. typedef uavcan::ServiceClient<root_ns_a::StringService,
  192. typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType;
  193. ServiceCallResultHandler<root_ns_a::StringService> handler;
  194. /*
  195. * Initializing
  196. */
  197. ClientType client(nodes.b);
  198. ASSERT_EQ(0, client.getNumPendingCalls());
  199. client.setCallback(handler.bind());
  200. ASSERT_EQ(1, nodes.a.getDispatcher().getNumServiceRequestListeners());
  201. ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // NOT listening!
  202. ASSERT_FALSE(client.hasPendingCalls());
  203. ASSERT_EQ(0, client.getNumPendingCalls());
  204. /*
  205. * Calling ten requests, the last one will be cancelled
  206. * Note that there will be non-unique transfer ID values; the client must handle that correctly
  207. */
  208. uavcan::ServiceCallID last_call_id;
  209. for (int i = 0; i < 10; i++)
  210. {
  211. std::ostringstream os;
  212. os << i;
  213. root_ns_a::StringService::Request request;
  214. request.string_request = os.str().c_str();
  215. ASSERT_LT(0, client.call(1, request, last_call_id));
  216. }
  217. ASSERT_LT(0, client.call(99, root_ns_a::StringService::Request())); // Will timeout in 1000 ms
  218. client.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));
  219. ASSERT_LT(0, client.call(88, root_ns_a::StringService::Request())); // Will timeout in 100 ms
  220. ASSERT_TRUE(client.hasPendingCalls());
  221. ASSERT_EQ(12, client.getNumPendingCalls());
  222. ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Listening
  223. /*
  224. * Cancelling one
  225. */
  226. client.cancelCall(last_call_id);
  227. ASSERT_TRUE(client.hasPendingCalls());
  228. ASSERT_EQ(11, client.getNumPendingCalls());
  229. ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Still listening
  230. /*
  231. * Spinning
  232. */
  233. nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(20));
  234. ASSERT_TRUE(client.hasPendingCalls());
  235. ASSERT_EQ(2, client.getNumPendingCalls()); // Two still pending
  236. ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Still listening
  237. /*
  238. * Validating the ones that didn't timeout
  239. */
  240. root_ns_a::StringService::Response last_response;
  241. for (int i = 0; i < 9; i++)
  242. {
  243. std::ostringstream os;
  244. os << "Request string: " << i;
  245. last_response.string_response = os.str().c_str();
  246. ASSERT_FALSE(handler.responses.empty());
  247. ASSERT_STREQ(last_response.string_response.c_str(), handler.responses.front().string_response.c_str());
  248. handler.responses.pop();
  249. }
  250. ASSERT_TRUE(handler.responses.empty());
  251. /*
  252. * Validating the 100 ms timeout
  253. */
  254. nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(100));
  255. ASSERT_TRUE(client.hasPendingCalls());
  256. ASSERT_EQ(1, client.getNumPendingCalls()); // One dropped
  257. ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Still listening
  258. ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 88, root_ns_a::StringService::Response()));
  259. /*
  260. * Validating the 1000 ms timeout
  261. */
  262. nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1000));
  263. ASSERT_FALSE(client.hasPendingCalls());
  264. ASSERT_EQ(0, client.getNumPendingCalls()); // All finished
  265. ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Not listening
  266. ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 99, root_ns_a::StringService::Response()));
  267. }
  268. TEST(ServiceClient, Empty)
  269. {
  270. InterlinkedTestNodesWithSysClock nodes;
  271. // Type registration
  272. uavcan::GlobalDataTypeRegistry::instance().reset();
  273. uavcan::DefaultDataTypeRegistrator<root_ns_a::EmptyService> _registrator;
  274. // Server
  275. uavcan::ServiceServer<root_ns_a::EmptyService> server(nodes.a);
  276. ASSERT_EQ(0, server.start(emptyServiceServerCallback));
  277. {
  278. // Caller
  279. typedef uavcan::ServiceClient<root_ns_a::EmptyService,
  280. typename ServiceCallResultHandler<root_ns_a::EmptyService>::Binder > ClientType;
  281. ServiceCallResultHandler<root_ns_a::EmptyService> handler;
  282. ClientType client(nodes.b);
  283. client.setCallback(handler.bind());
  284. root_ns_a::EmptyService::Request request;
  285. ASSERT_LT(0, client.call(1, request)); // OK
  286. }
  287. // All destroyed - nobody listening
  288. ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners());
  289. }
  290. TEST(ServiceClient, Priority)
  291. {
  292. InterlinkedTestNodesWithSysClock nodes;
  293. // Type registration
  294. uavcan::GlobalDataTypeRegistry::instance().reset();
  295. uavcan::DefaultDataTypeRegistrator<root_ns_a::EmptyService> _registrator;
  296. // Initializing
  297. typedef uavcan::ServiceClient<root_ns_a::EmptyService,
  298. typename ServiceCallResultHandler<root_ns_a::EmptyService>::Binder > ClientType;
  299. ServiceCallResultHandler<root_ns_a::EmptyService> handler;
  300. ClientType client(nodes.b);
  301. client.setCallback(handler.bind());
  302. // Calling
  303. root_ns_a::EmptyService::Request request;
  304. client.setPriority(0);
  305. ASSERT_LT(0, client.call(1, request)); // OK
  306. client.setPriority(10);
  307. ASSERT_LT(0, client.call(1, request)); // OK
  308. client.setPriority(20);
  309. ASSERT_LT(0, client.call(1, request)); // OK
  310. client.setPriority(31);
  311. ASSERT_LT(0, client.call(1, request)); // OK
  312. // Validating
  313. ASSERT_EQ(4, nodes.can_a.read_queue.size());
  314. uavcan::Frame frame;
  315. ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front()));
  316. nodes.can_a.read_queue.pop();
  317. ASSERT_EQ(0, frame.getPriority().get());
  318. ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front()));
  319. nodes.can_a.read_queue.pop();
  320. ASSERT_EQ(10, frame.getPriority().get());
  321. ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front()));
  322. nodes.can_a.read_queue.pop();
  323. ASSERT_EQ(20, frame.getPriority().get());
  324. ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front()));
  325. nodes.can_a.read_queue.pop();
  326. ASSERT_EQ(31, frame.getPriority().get());
  327. }
  328. TEST(ServiceClient, Sizes)
  329. {
  330. using namespace uavcan;
  331. std::cout << "GetDataTypeInfo server: " <<
  332. sizeof(ServiceServer<protocol::GetDataTypeInfo>) << std::endl;
  333. std::cout << "RestartNode server: " <<
  334. sizeof(ServiceServer<protocol::RestartNode>) << std::endl;
  335. std::cout << "GetDataTypeInfo client: " <<
  336. sizeof(ServiceClient<protocol::GetDataTypeInfo>) << std::endl;
  337. }