libuav original
Dependents: UAVCAN UAVCAN_Subscriber
service_client.cpp
00001 /* 00002 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com> 00003 */ 00004 00005 #include <gtest/gtest.h> 00006 #include <uavcan/node/service_client.hpp> 00007 #include <uavcan/node/service_server.hpp> 00008 #include <uavcan/util/method_binder.hpp> 00009 #include <uavcan/protocol/RestartNode.hpp> 00010 #include <uavcan/protocol/GetDataTypeInfo.hpp> 00011 #include <root_ns_a/StringService.hpp> 00012 #include <root_ns_a/EmptyService.hpp> 00013 #include <queue> 00014 #include <sstream> 00015 #include "test_node.hpp" 00016 00017 00018 template <typename DataType> 00019 struct ServiceCallResultHandler 00020 { 00021 typedef typename uavcan::ServiceCallResult<DataType>::Status StatusType; 00022 StatusType last_status; 00023 uavcan::NodeID last_server_node_id; 00024 typename DataType::Response last_response; 00025 std::queue<typename DataType::Response> responses; 00026 00027 void handleResponse(const uavcan::ServiceCallResult<DataType>& result) 00028 { 00029 std::cout << result << std::endl; 00030 last_status = result.getStatus(); 00031 last_response = result.getResponse(); 00032 last_server_node_id = result.getCallID().server_node_id; 00033 responses.push(result.getResponse()); 00034 } 00035 00036 bool match(StatusType status, uavcan::NodeID server_node_id, const typename DataType::Response& response) const 00037 { 00038 if (status == last_status && 00039 server_node_id == last_server_node_id && 00040 response == last_response) 00041 { 00042 return true; 00043 } 00044 else 00045 { 00046 std::cout << "MISMATCH: status=" << int(last_status) << ", last_server_node_id=" 00047 << int(last_server_node_id.get()) << ", last response:\n" << last_response << std::endl; 00048 return false; 00049 } 00050 } 00051 00052 typedef uavcan::MethodBinder<ServiceCallResultHandler*, 00053 void (ServiceCallResultHandler::*)(const uavcan::ServiceCallResult<DataType>&)> Binder; 00054 00055 Binder bind() { return Binder(this, &ServiceCallResultHandler::handleResponse); } 00056 }; 00057 00058 00059 static void stringServiceServerCallback(const uavcan::ReceivedDataStructure<root_ns_a::StringService::Request>& req, 00060 uavcan::ServiceResponseDataStructure<root_ns_a::StringService::Response>& rsp) 00061 { 00062 rsp.string_response = "Request string: "; 00063 rsp.string_response += req.string_request; 00064 } 00065 00066 static void rejectingStringServiceServerCallback( 00067 const uavcan::ReceivedDataStructure<root_ns_a::StringService::Request>& req, 00068 uavcan::ServiceResponseDataStructure<root_ns_a::StringService::Response>& rsp) 00069 { 00070 rsp.string_response = "Request string: "; 00071 rsp.string_response += req.string_request; 00072 ASSERT_TRUE(rsp.isResponseEnabled()); 00073 rsp.setResponseEnabled(false); 00074 ASSERT_FALSE(rsp.isResponseEnabled()); 00075 } 00076 00077 static void emptyServiceServerCallback(const uavcan::ReceivedDataStructure<root_ns_a::EmptyService::Request>&, 00078 uavcan::ServiceResponseDataStructure<root_ns_a::EmptyService::Response>&) 00079 { 00080 // Nothing to do - the service is empty 00081 } 00082 00083 00084 TEST(ServiceClient, Basic) 00085 { 00086 InterlinkedTestNodesWithSysClock nodes; 00087 00088 // Type registration 00089 uavcan::GlobalDataTypeRegistry::instance().reset(); 00090 uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator; 00091 00092 // Server 00093 uavcan::ServiceServer<root_ns_a::StringService> server(nodes.a); 00094 ASSERT_EQ(0, server.start(stringServiceServerCallback)); 00095 00096 { 00097 // Caller 00098 typedef uavcan::ServiceCallResult<root_ns_a::StringService> ResultType; 00099 typedef uavcan::ServiceClient<root_ns_a::StringService, 00100 typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType; 00101 ServiceCallResultHandler<root_ns_a::StringService> handler; 00102 00103 ClientType client1(nodes.b); 00104 ClientType client2(nodes.b); 00105 ClientType client3(nodes.b); 00106 00107 ASSERT_EQ(0, client1.getNumPendingCalls()); 00108 ASSERT_EQ(0, client2.getNumPendingCalls()); 00109 ASSERT_EQ(0, client3.getNumPendingCalls()); 00110 00111 ASSERT_FALSE(client1.hasPendingCallToServer(1)); 00112 00113 client1.setCallback(handler.bind()); 00114 client2.setCallback(client1.getCallback()); 00115 client3.setCallback(client1.getCallback()); 00116 client3.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100)); 00117 00118 ASSERT_EQ(1, nodes.a.getDispatcher().getNumServiceRequestListeners()); 00119 ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // NOT listening! 00120 00121 root_ns_a::StringService::Request request; 00122 request.string_request = "Hello world"; 00123 00124 std::cout << "!!! Calling!" << std::endl; 00125 00126 ASSERT_LT(0, client1.call(1, request)); // OK 00127 ASSERT_LT(0, client1.call(1, request)); // OK - second request 00128 ASSERT_LT(0, client2.call(1, request)); // OK 00129 ASSERT_LT(0, client3.call(99, request)); // Will timeout! 00130 ASSERT_LT(0, client3.call(1, request)); // OK - second request 00131 00132 ASSERT_TRUE(client1.hasPendingCallToServer(1)); 00133 ASSERT_TRUE(client2.hasPendingCallToServer(1)); 00134 ASSERT_TRUE(client3.hasPendingCallToServer(99)); 00135 ASSERT_TRUE(client3.hasPendingCallToServer(1)); 00136 00137 std::cout << "!!! Spinning!" << std::endl; 00138 00139 ASSERT_EQ(3, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Listening now! 00140 00141 ASSERT_TRUE(client1.hasPendingCalls()); 00142 ASSERT_TRUE(client2.hasPendingCalls()); 00143 ASSERT_TRUE(client3.hasPendingCalls()); 00144 00145 ASSERT_EQ(2, client1.getNumPendingCalls()); 00146 ASSERT_EQ(1, client2.getNumPendingCalls()); 00147 ASSERT_EQ(2, client3.getNumPendingCalls()); 00148 00149 ASSERT_EQ(uavcan::NodeID(1), client2.getCallIDByIndex(0).server_node_id); 00150 ASSERT_EQ(uavcan::NodeID(), client2.getCallIDByIndex(1).server_node_id); 00151 00152 nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(20)); 00153 00154 std::cout << "!!! Spin finished!" << std::endl; 00155 00156 ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Third is still listening! 00157 00158 ASSERT_FALSE(client1.hasPendingCalls()); 00159 ASSERT_FALSE(client2.hasPendingCalls()); 00160 ASSERT_TRUE(client3.hasPendingCalls()); 00161 00162 ASSERT_EQ(0, client1.getNumPendingCalls()); 00163 ASSERT_EQ(0, client2.getNumPendingCalls()); 00164 ASSERT_EQ(1, client3.getNumPendingCalls()); // The one addressed to 99 is still waiting 00165 00166 // Validating 00167 root_ns_a::StringService::Response expected_response; 00168 expected_response.string_response = "Request string: Hello world"; 00169 ASSERT_TRUE(handler.match(ResultType::Success, 1, expected_response)); 00170 00171 nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(200)); 00172 00173 ASSERT_FALSE(client1.hasPendingCalls()); 00174 ASSERT_FALSE(client2.hasPendingCalls()); 00175 ASSERT_FALSE(client3.hasPendingCalls()); 00176 00177 ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Third has timed out :( 00178 00179 // Validating 00180 ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 99, root_ns_a::StringService::Response())); 00181 00182 // Stray request 00183 ASSERT_LT(0, client3.call(99, request)); // Will timeout! 00184 ASSERT_TRUE(client3.hasPendingCalls()); 00185 ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); 00186 } 00187 00188 // All destroyed - nobody listening 00189 ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); 00190 } 00191 00192 00193 TEST(ServiceClient, Rejection) 00194 { 00195 InterlinkedTestNodesWithSysClock nodes; 00196 00197 // Type registration 00198 uavcan::GlobalDataTypeRegistry::instance().reset(); 00199 uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator; 00200 00201 // Server 00202 uavcan::ServiceServer<root_ns_a::StringService> server(nodes.a); 00203 ASSERT_EQ(0, server.start(rejectingStringServiceServerCallback)); 00204 00205 // Caller 00206 typedef uavcan::ServiceCallResult<root_ns_a::StringService> ResultType; 00207 typedef uavcan::ServiceClient<root_ns_a::StringService, 00208 typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType; 00209 ServiceCallResultHandler<root_ns_a::StringService> handler; 00210 00211 ClientType client1(nodes.b); 00212 client1.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100)); 00213 client1.setCallback(handler.bind()); 00214 00215 root_ns_a::StringService::Request request; 00216 request.string_request = "Hello world"; 00217 00218 ASSERT_LT(0, client1.call(1, request)); 00219 00220 ASSERT_EQ(uavcan::NodeID(1), client1.getCallIDByIndex(0).server_node_id); 00221 ASSERT_EQ(uavcan::NodeID(), client1.getCallIDByIndex(1).server_node_id); 00222 00223 ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); 00224 ASSERT_TRUE(client1.hasPendingCalls()); 00225 ASSERT_TRUE(client1.hasPendingCallToServer(1)); 00226 00227 nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(200)); 00228 ASSERT_FALSE(client1.hasPendingCalls()); 00229 ASSERT_FALSE(client1.hasPendingCallToServer(1)); 00230 00231 ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Timed out 00232 00233 ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 1, root_ns_a::StringService::Response())); 00234 } 00235 00236 00237 TEST(ServiceClient, ConcurrentCalls) 00238 { 00239 InterlinkedTestNodesWithSysClock nodes; 00240 00241 // Type registration 00242 uavcan::GlobalDataTypeRegistry::instance().reset(); 00243 uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator; 00244 00245 // Server 00246 uavcan::ServiceServer<root_ns_a::StringService> server(nodes.a); 00247 ASSERT_EQ(0, server.start(stringServiceServerCallback)); 00248 00249 // Caller 00250 typedef uavcan::ServiceCallResult<root_ns_a::StringService> ResultType; 00251 typedef uavcan::ServiceClient<root_ns_a::StringService, 00252 typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType; 00253 ServiceCallResultHandler<root_ns_a::StringService> handler; 00254 00255 /* 00256 * Initializing 00257 */ 00258 ClientType client(nodes.b); 00259 00260 ASSERT_EQ(0, client.getNumPendingCalls()); 00261 00262 client.setCallback(handler.bind()); 00263 00264 ASSERT_EQ(1, nodes.a.getDispatcher().getNumServiceRequestListeners()); 00265 ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // NOT listening! 00266 00267 ASSERT_FALSE(client.hasPendingCalls()); 00268 ASSERT_EQ(0, client.getNumPendingCalls()); 00269 00270 /* 00271 * Calling ten requests, the last one will be cancelled 00272 * Note that there will be non-unique transfer ID values; the client must handle that correctly 00273 */ 00274 uavcan::ServiceCallID last_call_id; 00275 for (int i = 0; i < 10; i++) 00276 { 00277 std::ostringstream os; 00278 os << i; 00279 root_ns_a::StringService::Request request; 00280 request.string_request = os.str().c_str(); 00281 ASSERT_LT(0, client.call(1, request, last_call_id)); 00282 } 00283 00284 ASSERT_LT(0, client.call(99, root_ns_a::StringService::Request())); // Will timeout in 1000 ms 00285 00286 client.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100)); 00287 00288 ASSERT_LT(0, client.call(88, root_ns_a::StringService::Request())); // Will timeout in 100 ms 00289 00290 ASSERT_TRUE(client.hasPendingCalls()); 00291 ASSERT_EQ(12, client.getNumPendingCalls()); 00292 00293 ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Listening 00294 00295 /* 00296 * Cancelling one 00297 */ 00298 client.cancelCall(last_call_id); 00299 00300 ASSERT_TRUE(client.hasPendingCalls()); 00301 ASSERT_EQ(11, client.getNumPendingCalls()); 00302 00303 ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Still listening 00304 00305 /* 00306 * Spinning 00307 */ 00308 nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(20)); 00309 00310 ASSERT_TRUE(client.hasPendingCalls()); 00311 ASSERT_EQ(2, client.getNumPendingCalls()); // Two still pending 00312 ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Still listening 00313 00314 /* 00315 * Validating the ones that didn't timeout 00316 */ 00317 root_ns_a::StringService::Response last_response; 00318 for (int i = 0; i < 9; i++) 00319 { 00320 std::ostringstream os; 00321 os << "Request string: " << i; 00322 last_response.string_response = os.str().c_str(); 00323 00324 ASSERT_FALSE(handler.responses.empty()); 00325 00326 ASSERT_STREQ(last_response.string_response.c_str(), handler.responses.front().string_response.c_str()); 00327 00328 handler.responses.pop(); 00329 } 00330 00331 ASSERT_TRUE(handler.responses.empty()); 00332 00333 /* 00334 * Validating the 100 ms timeout 00335 */ 00336 nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(100)); 00337 00338 ASSERT_TRUE(client.hasPendingCalls()); 00339 ASSERT_EQ(1, client.getNumPendingCalls()); // One dropped 00340 ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Still listening 00341 00342 ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 88, root_ns_a::StringService::Response())); 00343 00344 /* 00345 * Validating the 1000 ms timeout 00346 */ 00347 nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1000)); 00348 00349 ASSERT_FALSE(client.hasPendingCalls()); 00350 ASSERT_EQ(0, client.getNumPendingCalls()); // All finished 00351 ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Not listening 00352 00353 ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 99, root_ns_a::StringService::Response())); 00354 } 00355 00356 00357 TEST(ServiceClient, Empty) 00358 { 00359 InterlinkedTestNodesWithSysClock nodes; 00360 00361 // Type registration 00362 uavcan::GlobalDataTypeRegistry::instance().reset(); 00363 uavcan::DefaultDataTypeRegistrator<root_ns_a::EmptyService> _registrator; 00364 00365 // Server 00366 uavcan::ServiceServer<root_ns_a::EmptyService> server(nodes.a); 00367 ASSERT_EQ(0, server.start(emptyServiceServerCallback)); 00368 00369 { 00370 // Caller 00371 typedef uavcan::ServiceClient<root_ns_a::EmptyService, 00372 typename ServiceCallResultHandler<root_ns_a::EmptyService>::Binder > ClientType; 00373 ServiceCallResultHandler<root_ns_a::EmptyService> handler; 00374 00375 ClientType client(nodes.b); 00376 00377 client.setCallback(handler.bind()); 00378 00379 root_ns_a::EmptyService::Request request; 00380 00381 ASSERT_LT(0, client.call(1, request)); // OK 00382 } 00383 00384 // All destroyed - nobody listening 00385 ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); 00386 } 00387 00388 00389 TEST(ServiceClient, Priority) 00390 { 00391 InterlinkedTestNodesWithSysClock nodes; 00392 00393 // Type registration 00394 uavcan::GlobalDataTypeRegistry::instance().reset(); 00395 uavcan::DefaultDataTypeRegistrator<root_ns_a::EmptyService> _registrator; 00396 00397 // Initializing 00398 typedef uavcan::ServiceClient<root_ns_a::EmptyService, 00399 typename ServiceCallResultHandler<root_ns_a::EmptyService>::Binder > ClientType; 00400 ServiceCallResultHandler<root_ns_a::EmptyService> handler; 00401 ClientType client(nodes.b); 00402 client.setCallback(handler.bind()); 00403 00404 // Calling 00405 root_ns_a::EmptyService::Request request; 00406 00407 client.setPriority(0); 00408 ASSERT_LT(0, client.call(1, request)); // OK 00409 00410 client.setPriority(10); 00411 ASSERT_LT(0, client.call(1, request)); // OK 00412 00413 client.setPriority(20); 00414 ASSERT_LT(0, client.call(1, request)); // OK 00415 00416 client.setPriority(31); 00417 ASSERT_LT(0, client.call(1, request)); // OK 00418 00419 // Validating 00420 ASSERT_EQ(4, nodes.can_a.read_queue.size()); 00421 00422 uavcan::Frame frame; 00423 00424 ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front())); 00425 nodes.can_a.read_queue.pop(); 00426 ASSERT_EQ(0, frame.getPriority().get()); 00427 00428 ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front())); 00429 nodes.can_a.read_queue.pop(); 00430 ASSERT_EQ(10, frame.getPriority().get()); 00431 00432 ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front())); 00433 nodes.can_a.read_queue.pop(); 00434 ASSERT_EQ(20, frame.getPriority().get()); 00435 00436 ASSERT_TRUE(frame.parse(nodes.can_a.read_queue.front())); 00437 nodes.can_a.read_queue.pop(); 00438 ASSERT_EQ(31, frame.getPriority().get()); 00439 } 00440 00441 00442 TEST(ServiceClient, Sizes) 00443 { 00444 using namespace uavcan; 00445 00446 std::cout << "GetDataTypeInfo server: " << 00447 sizeof(ServiceServer<protocol::GetDataTypeInfo>) << std::endl; 00448 00449 std::cout << "RestartNode server: " << 00450 sizeof(ServiceServer<protocol::RestartNode>) << std::endl; 00451 00452 std::cout << "GetDataTypeInfo client: " << 00453 sizeof(ServiceClient<protocol::GetDataTypeInfo>) << std::endl; 00454 }
Generated on Tue Jul 12 2022 17:17:34 by 1.7.2