libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers service_client.cpp Source File

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 }