Exemplo n.º 1
0
TEST(PanicListener, Basic)
{
    InterlinkedTestNodesWithSysClock nodes;

    uavcan::GlobalDataTypeRegistry::instance().reset();
    uavcan::DefaultDataTypeRegistrator<uavcan::protocol::Panic> _reg1;

    uavcan::PanicListener<PanicHandler::Binder> pl(nodes.a);
    uavcan::PanicBroadcaster pbr(nodes.b);
    PanicHandler handler;
    ASSERT_LE(0, pl.start(handler.bind()));

    pbr.panic("PANIC!!!");
    ASSERT_TRUE(handler.msg == uavcan::protocol::Panic()); // One message published, panic is not registered yet

    pbr.dontPanic();
    ASSERT_FALSE(pbr.isPanicking());
    std::cout << "Not panicking" << std::endl;

    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1000)); // Will reset
    ASSERT_TRUE(handler.msg == uavcan::protocol::Panic());

    pbr.panic("PANIC2!!!");     // Message text doesn't matter
    ASSERT_TRUE(pbr.isPanicking());
    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1000));
    ASSERT_STREQ("PANIC2!", handler.msg.reason_text.c_str()); // Registered, only 7 chars preserved
}
Exemplo n.º 2
0
TEST(Logger, Cpp11Formatting)
{
    InterlinkedTestNodesWithSysClock nodes;

    uavcan::Logger logger(nodes.a);
    logger.setLevel(uavcan::protocol::debug::LogLevel::DEBUG);

    SubscriberWithCollector<uavcan::protocol::debug::LogMessage> log_sub(nodes.b);
    ASSERT_LE(0, log_sub.start());

    ASSERT_LE(0, logger.logWarning("foo", "char='%*', %* is %*", '$', "double", 12.34));
    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10));
    ASSERT_TRUE(log_sub.collector.msg.get());
    ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::WARNING);
    ASSERT_EQ(log_sub.collector.msg->source, "foo");
    ASSERT_EQ(log_sub.collector.msg->text, "char='$', double is 12.34");
}
Exemplo n.º 3
0
TEST(ServiceClient, Rejection)
{
    InterlinkedTestNodesWithSysClock nodes;

    // Type registration
    uavcan::GlobalDataTypeRegistry::instance().reset();
    uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator;

    // Server
    uavcan::ServiceServer<root_ns_a::StringService> server(nodes.a);
    ASSERT_EQ(0, server.start(rejectingStringServiceServerCallback));

    // Caller
    typedef uavcan::ServiceCallResult<root_ns_a::StringService> ResultType;
    typedef uavcan::ServiceClient<root_ns_a::StringService,
                                  typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType;
    ServiceCallResultHandler<root_ns_a::StringService> handler;

    ClientType client1(nodes.b);
    client1.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));
    client1.setCallback(handler.bind());

    root_ns_a::StringService::Request request;
    request.string_request = "Hello world";

    ASSERT_LT(0, client1.call(1, request));

    ASSERT_EQ(uavcan::NodeID(1), client1.getCallIDByIndex(0).server_node_id);
    ASSERT_EQ(uavcan::NodeID(), client1.getCallIDByIndex(1).server_node_id);

    ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());
    ASSERT_TRUE(client1.hasPendingCalls());
    ASSERT_TRUE(client1.hasPendingCallToServer(1));

    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(200));
    ASSERT_FALSE(client1.hasPendingCalls());
    ASSERT_FALSE(client1.hasPendingCallToServer(1));

    ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Timed out

    ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 1, root_ns_a::StringService::Response()));
}
Exemplo n.º 4
0
TEST(Logger, Basic)
{
    InterlinkedTestNodesWithSysClock nodes;

    uavcan::Logger logger(nodes.a);

    ASSERT_EQ(uavcan::protocol::debug::LogLevel::ERROR, logger.getLevel());

    LogSink sink;

    // Will fail - types are not registered
    uavcan::GlobalDataTypeRegistry::instance().reset();
    ASSERT_GT(0, logger.logError("foo", "Error (fail - type is not registered)"));
    ASSERT_EQ(0, logger.logDebug("foo", "Debug (ignored - low logging level)"));

    ASSERT_FALSE(logger.getExternalSink());
    logger.setExternalSink(&sink);
    ASSERT_EQ(&sink, logger.getExternalSink());

    uavcan::GlobalDataTypeRegistry::instance().reset();
    uavcan::DefaultDataTypeRegistrator<uavcan::protocol::debug::LogMessage> _reg1;

    SubscriberWithCollector<uavcan::protocol::debug::LogMessage> log_sub(nodes.b);
    ASSERT_LE(0, log_sub.start());

    // Sink test
    ASSERT_EQ(0, logger.logDebug("foo", "Debug (ignored due to low logging level)"));
    ASSERT_TRUE(sink.msgs.empty());

    sink.level = uavcan::protocol::debug::LogLevel::DEBUG;
    ASSERT_EQ(0, logger.logDebug("foo", "Debug (sink only)"));
    ASSERT_TRUE(sink.popMatchByLevelAndText(uavcan::protocol::debug::LogLevel::DEBUG, "foo", "Debug (sink only)"));

    ASSERT_LE(0, logger.logError("foo", "Error"));
    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10));
    ASSERT_TRUE(log_sub.collector.msg.get());
    ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::ERROR);
    ASSERT_EQ(log_sub.collector.msg->source, "foo");
    ASSERT_EQ(log_sub.collector.msg->text, "Error");

    logger.setLevel(uavcan::protocol::debug::LogLevel::DEBUG);
    ASSERT_LE(0, logger.logWarning("foo", "Warning"));
    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10));
    ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::WARNING);
    ASSERT_EQ(log_sub.collector.msg->source, "foo");
    ASSERT_EQ(log_sub.collector.msg->text, "Warning");

    ASSERT_LE(0, logger.logInfo("foo", "Info"));
    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10));
    ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::INFO);
    ASSERT_EQ(log_sub.collector.msg->source, "foo");
    ASSERT_EQ(log_sub.collector.msg->text, "Info");

    ASSERT_LE(0, logger.logDebug("foo", "Debug"));
    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10));
    ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::DEBUG);
    ASSERT_EQ(log_sub.collector.msg->source, "foo");
    ASSERT_EQ(log_sub.collector.msg->text, "Debug");

    ASSERT_TRUE(sink.popMatchByLevelAndText(uavcan::protocol::debug::LogLevel::ERROR,   "foo", "Error"));
    ASSERT_TRUE(sink.popMatchByLevelAndText(uavcan::protocol::debug::LogLevel::WARNING, "foo", "Warning"));
    ASSERT_TRUE(sink.popMatchByLevelAndText(uavcan::protocol::debug::LogLevel::INFO,    "foo", "Info"));
    ASSERT_TRUE(sink.popMatchByLevelAndText(uavcan::protocol::debug::LogLevel::DEBUG,   "foo", "Debug"));
}
TEST(DataTypeInfoProvider, Basic)
{
    InterlinkedTestNodesWithSysClock nodes;

    DataTypeInfoProvider dtip(nodes.a);

    GlobalDataTypeRegistry::instance().reset();
    DefaultDataTypeRegistrator<GetDataTypeInfo> _reg1;
    DefaultDataTypeRegistrator<ComputeAggregateTypeSignature> _reg2;
    DefaultDataTypeRegistrator<NodeStatus> _reg3;

    ASSERT_LE(0, dtip.start());

    ServiceClientWithCollector<GetDataTypeInfo> gdti_cln(nodes.b);
    ServiceClientWithCollector<ComputeAggregateTypeSignature> cats_cln(nodes.b);

    /*
     * GetDataTypeInfo request for GetDataTypeInfo
     */
    GetDataTypeInfo::Request gdti_request;
    gdti_request.id = GetDataTypeInfo::DefaultDataTypeID;
    gdti_request.kind.value = DataTypeKind::SERVICE;
    ASSERT_LE(0, gdti_cln.call(1, gdti_request));
    nodes.spinBoth(MonotonicDuration::fromMSec(10));

    ASSERT_TRUE(validateDataTypeInfoResponse<GetDataTypeInfo>(gdti_cln.collector.result,
                                                              GetDataTypeInfo::Response::MASK_KNOWN |
                                                              GetDataTypeInfo::Response::MASK_SERVING));
    ASSERT_EQ(1, gdti_cln.collector.result->getCallID().server_node_id.get());

    /*
     * GetDataTypeInfo request for GetDataTypeInfo by name
     */
    gdti_request = GetDataTypeInfo::Request();
    gdti_request.id = 999;                             // Intentionally wrong
    gdti_request.kind.value = DataTypeKind::MESSAGE;   // Intentionally wrong
    gdti_request.name = "uavcan.protocol.GetDataTypeInfo";
    ASSERT_LE(0, gdti_cln.call(1, gdti_request));
    nodes.spinBoth(MonotonicDuration::fromMSec(10));

    ASSERT_TRUE(validateDataTypeInfoResponse<GetDataTypeInfo>(gdti_cln.collector.result,
                                                              GetDataTypeInfo::Response::MASK_KNOWN |
                                                              GetDataTypeInfo::Response::MASK_SERVING));
    ASSERT_EQ(1, gdti_cln.collector.result->getCallID().server_node_id.get());

    /*
     * GetDataTypeInfo request for NodeStatus - not used yet
     */
    gdti_request = GetDataTypeInfo::Request();
    gdti_request.id = NodeStatus::DefaultDataTypeID;
    gdti_request.kind.value = DataTypeKind::MESSAGE;
    ASSERT_LE(0, gdti_cln.call(1, gdti_request));
    nodes.spinBoth(MonotonicDuration::fromMSec(10));

    ASSERT_TRUE(validateDataTypeInfoResponse<NodeStatus>(gdti_cln.collector.result,
                                                         GetDataTypeInfo::Response::MASK_KNOWN));

    /*
     * Starting publisher and subscriber for NodeStatus, requesting info again
     */
    uavcan::Publisher<NodeStatus> ns_pub(nodes.a);
    SubscriberWithCollector<NodeStatus> ns_sub(nodes.a);

    ASSERT_LE(0, ns_pub.broadcast(NodeStatus()));
    ASSERT_LE(0, ns_sub.start());

    // Request again
    ASSERT_LE(0, gdti_cln.call(1, gdti_request));
    nodes.spinBoth(MonotonicDuration::fromMSec(10));

    ASSERT_TRUE(validateDataTypeInfoResponse<NodeStatus>(gdti_cln.collector.result,
                                                         GetDataTypeInfo::Response::MASK_KNOWN |
                                                         GetDataTypeInfo::Response::MASK_PUBLISHING |
                                                         GetDataTypeInfo::Response::MASK_SUBSCRIBED));

    /*
     * Requesting a non-existent type
     */
    gdti_request = GetDataTypeInfo::Request();
    gdti_request.id = ComputeAggregateTypeSignature::DefaultDataTypeID;
    gdti_request.kind.value = 3;                 // INVALID VALUE
    ASSERT_LE(0, gdti_cln.call(1, gdti_request));
    nodes.spinBoth(MonotonicDuration::fromMSec(10));

    ASSERT_TRUE(gdti_cln.collector.result.get());
    ASSERT_TRUE(gdti_cln.collector.result->isSuccessful());
    ASSERT_EQ(1, gdti_cln.collector.result->getCallID().server_node_id.get());
    ASSERT_EQ(0, gdti_cln.collector.result->getResponse().mask);
    ASSERT_TRUE(gdti_cln.collector.result->getResponse().name.empty());  // Empty name
    ASSERT_EQ(gdti_request.id, gdti_cln.collector.result->getResponse().id);
    ASSERT_EQ(gdti_request.kind.value, gdti_cln.collector.result->getResponse().kind.value);

    /*
     * Requesting a non-existent type by name
     */
    gdti_request = GetDataTypeInfo::Request();
    gdti_request.id = 999;                        // Intentionally wrong
    gdti_request.kind.value = 3;                  // Intentionally wrong
    gdti_request.name = "uavcan.equipment.gnss.Fix";
    ASSERT_LE(0, gdti_cln.call(1, gdti_request));
    nodes.spinBoth(MonotonicDuration::fromMSec(10));

    ASSERT_TRUE(gdti_cln.collector.result.get());
    ASSERT_TRUE(gdti_cln.collector.result->isSuccessful());
    ASSERT_EQ(1, gdti_cln.collector.result->getCallID().server_node_id.get());
    ASSERT_EQ(0, gdti_cln.collector.result->getResponse().mask);
    ASSERT_EQ("uavcan.equipment.gnss.Fix", gdti_cln.collector.result->getResponse().name);
    ASSERT_EQ(0, gdti_cln.collector.result->getResponse().id);
    ASSERT_EQ(0, gdti_cln.collector.result->getResponse().kind.value);

    /*
     * ComputeAggregateTypeSignature test for messages
     */
    ComputeAggregateTypeSignature::Request cats_request;
    cats_request.kind.value = DataTypeKind::MESSAGE;
    cats_request.known_ids.resize(2000); // not 2048
    cats_request.known_ids.set();                   // Assuming we have all 2000 types
    ASSERT_LE(0, cats_cln.call(1, cats_request));
    nodes.spinBoth(MonotonicDuration::fromMSec(10));

    ASSERT_TRUE(cats_cln.collector.result.get());
    ASSERT_TRUE(cats_cln.collector.result->isSuccessful());
    ASSERT_EQ(1, cats_cln.collector.result->getCallID().server_node_id.get());
    ASSERT_EQ(NodeStatus::getDataTypeSignature().get(), cats_cln.collector.result->getResponse().aggregate_signature);
    ASSERT_EQ(2048, cats_cln.collector.result->getResponse().mutually_known_ids.size());
    ASSERT_TRUE(cats_cln.collector.result->getResponse().mutually_known_ids[NodeStatus::DefaultDataTypeID]);
    cats_cln.collector.result->getResponse().mutually_known_ids[NodeStatus::DefaultDataTypeID] = false;
    ASSERT_FALSE(cats_cln.collector.result->getResponse().mutually_known_ids.any());

    /*
     * ComputeAggregateTypeSignature test for services
     */
    cats_request = ComputeAggregateTypeSignature::Request();
    cats_request.kind.value = DataTypeKind::SERVICE;
    cats_request.known_ids.resize(500); // not 512
    cats_request.known_ids.set();                   // Assuming we have all 500 types
    ASSERT_LE(0, cats_cln.call(1, cats_request));
    nodes.spinBoth(MonotonicDuration::fromMSec(10));

    ASSERT_TRUE(cats_cln.collector.result.get());
    ASSERT_TRUE(cats_cln.collector.result->isSuccessful());
    ASSERT_EQ(1, cats_cln.collector.result->getCallID().server_node_id.get());
    ASSERT_EQ(512, cats_cln.collector.result->getResponse().mutually_known_ids.size());
    ASSERT_TRUE(cats_cln.collector.result->getResponse().mutually_known_ids[GetDataTypeInfo::DefaultDataTypeID]);
    ASSERT_TRUE(cats_cln.collector.result->getResponse().mutually_known_ids[ComputeAggregateTypeSignature::DefaultDataTypeID]);
    cats_cln.collector.result->getResponse().mutually_known_ids[GetDataTypeInfo::DefaultDataTypeID] = false;
    cats_cln.collector.result->getResponse().mutually_known_ids[ComputeAggregateTypeSignature::DefaultDataTypeID] = false;
    ASSERT_FALSE(cats_cln.collector.result->getResponse().mutually_known_ids.any());

    /*
     * ComputeAggregateTypeSignature test for a non-existent type
     */
    cats_request.kind.value = 0xFF;                 // INVALID
    cats_request.known_ids.set();                   // Assuming we have all 2048 types
    ASSERT_LE(0, cats_cln.call(1, cats_request));
    nodes.spinBoth(MonotonicDuration::fromMSec(10));

    ASSERT_TRUE(cats_cln.collector.result.get());
    ASSERT_TRUE(cats_cln.collector.result->isSuccessful());
    ASSERT_EQ(0, cats_cln.collector.result->getResponse().aggregate_signature);
    ASSERT_FALSE(cats_cln.collector.result->getResponse().mutually_known_ids.any());
}
Exemplo n.º 6
0
TEST(TransportStatsProvider, Basic)
{
    InterlinkedTestNodesWithSysClock nodes;

    uavcan::TransportStatsProvider tsp(nodes.a);

    uavcan::GlobalDataTypeRegistry::instance().reset();
    uavcan::DefaultDataTypeRegistrator<uavcan::protocol::GetTransportStats> _reg1;

    ASSERT_LE(0, tsp.start());

    ServiceClientWithCollector<uavcan::protocol::GetTransportStats> tsp_cln(nodes.b);

    /*
     * First request
     */
    ASSERT_LE(0, tsp_cln.call(1, uavcan::protocol::GetTransportStats::Request()));
    ASSERT_LE(0, nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10)));

    ASSERT_TRUE(tsp_cln.collector.result.get());
    ASSERT_TRUE(tsp_cln.collector.result->isSuccessful());
    ASSERT_EQ(0, tsp_cln.collector.result->response.transfer_errors);
    ASSERT_EQ(1, tsp_cln.collector.result->response.transfers_rx);
    ASSERT_EQ(0, tsp_cln.collector.result->response.transfers_tx);
    ASSERT_EQ(1, tsp_cln.collector.result->response.can_iface_stats.size());
    ASSERT_EQ(0, tsp_cln.collector.result->response.can_iface_stats[0].errors);
    ASSERT_EQ(1, tsp_cln.collector.result->response.can_iface_stats[0].frames_rx);
    ASSERT_EQ(0, tsp_cln.collector.result->response.can_iface_stats[0].frames_tx);

    /*
     * Second request
     */
    ASSERT_LE(0, tsp_cln.call(1, uavcan::protocol::GetTransportStats::Request()));
    ASSERT_LE(0, nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10)));

    ASSERT_TRUE(tsp_cln.collector.result.get());
    ASSERT_EQ(0, tsp_cln.collector.result->response.transfer_errors);
    ASSERT_EQ(2, tsp_cln.collector.result->response.transfers_rx);
    ASSERT_EQ(1, tsp_cln.collector.result->response.transfers_tx);
    ASSERT_EQ(1, tsp_cln.collector.result->response.can_iface_stats.size());
    ASSERT_EQ(0, tsp_cln.collector.result->response.can_iface_stats[0].errors);
    ASSERT_EQ(2, tsp_cln.collector.result->response.can_iface_stats[0].frames_rx);
    ASSERT_EQ(6, tsp_cln.collector.result->response.can_iface_stats[0].frames_tx);

    /*
     * Sending a malformed frame, it must be registered as tranfer error
     */
    uavcan::Frame frame(uavcan::protocol::GetTransportStats::DefaultDataTypeID, uavcan::TransferTypeServiceRequest,
                        2, 1, 0, 0, true);
    uavcan::CanFrame can_frame;
    ASSERT_TRUE(frame.compile(can_frame));
    nodes.can_a.read_queue.push(can_frame);

    ASSERT_LE(0, nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10)));

    /*
     * Introducing a CAN driver error
     */
    nodes.can_a.error_count = 72;

    /*
     * Third request
     */
    ASSERT_LE(0, tsp_cln.call(1, uavcan::protocol::GetTransportStats::Request()));
    ASSERT_LE(0, nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10)));

    ASSERT_TRUE(tsp_cln.collector.result.get());
    ASSERT_EQ(1, tsp_cln.collector.result->response.transfer_errors);                  // That broken frame
    ASSERT_EQ(3, tsp_cln.collector.result->response.transfers_rx);
    ASSERT_EQ(2, tsp_cln.collector.result->response.transfers_tx);
    ASSERT_EQ(1, tsp_cln.collector.result->response.can_iface_stats.size());
    ASSERT_EQ(72, tsp_cln.collector.result->response.can_iface_stats[0].errors);
    ASSERT_EQ(4, tsp_cln.collector.result->response.can_iface_stats[0].frames_rx);     // Same here
    ASSERT_EQ(12, tsp_cln.collector.result->response.can_iface_stats[0].frames_tx);
}
Exemplo n.º 7
0
TEST(ServiceClient, Basic)
{
    InterlinkedTestNodesWithSysClock nodes;

    // Type registration
    uavcan::GlobalDataTypeRegistry::instance().reset();
    uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator;

    // Server
    uavcan::ServiceServer<root_ns_a::StringService> server(nodes.a);
    ASSERT_EQ(0, server.start(stringServiceServerCallback));

    {
        // Caller
        typedef uavcan::ServiceCallResult<root_ns_a::StringService> ResultType;
        typedef uavcan::ServiceClient<root_ns_a::StringService,
                                      typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType;
        ServiceCallResultHandler<root_ns_a::StringService> handler;

        ClientType client1(nodes.b);
        ClientType client2(nodes.b);
        ClientType client3(nodes.b);

        ASSERT_EQ(0, client1.getNumPendingCalls());
        ASSERT_EQ(0, client2.getNumPendingCalls());
        ASSERT_EQ(0, client3.getNumPendingCalls());

        ASSERT_FALSE(client1.hasPendingCallToServer(1));

        client1.setCallback(handler.bind());
        client2.setCallback(client1.getCallback());
        client3.setCallback(client1.getCallback());
        client3.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));

        ASSERT_EQ(1, nodes.a.getDispatcher().getNumServiceRequestListeners());
        ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // NOT listening!

        root_ns_a::StringService::Request request;
        request.string_request = "Hello world";

        std::cout << "!!! Calling!" << std::endl;

        ASSERT_LT(0, client1.call(1, request)); // OK
        ASSERT_LT(0, client1.call(1, request)); // OK - second request
        ASSERT_LT(0, client2.call(1, request)); // OK
        ASSERT_LT(0, client3.call(99, request)); // Will timeout!
        ASSERT_LT(0, client3.call(1, request)); // OK - second request

        ASSERT_TRUE(client1.hasPendingCallToServer(1));
        ASSERT_TRUE(client2.hasPendingCallToServer(1));
        ASSERT_TRUE(client3.hasPendingCallToServer(99));
        ASSERT_TRUE(client3.hasPendingCallToServer(1));

        std::cout << "!!! Spinning!" << std::endl;

        ASSERT_EQ(3, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Listening now!

        ASSERT_TRUE(client1.hasPendingCalls());
        ASSERT_TRUE(client2.hasPendingCalls());
        ASSERT_TRUE(client3.hasPendingCalls());

        ASSERT_EQ(2, client1.getNumPendingCalls());
        ASSERT_EQ(1, client2.getNumPendingCalls());
        ASSERT_EQ(2, client3.getNumPendingCalls());

        ASSERT_EQ(uavcan::NodeID(1), client2.getCallIDByIndex(0).server_node_id);
        ASSERT_EQ(uavcan::NodeID(), client2.getCallIDByIndex(1).server_node_id);

        nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(20));

        std::cout << "!!! Spin finished!" << std::endl;

        ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Third is still listening!

        ASSERT_FALSE(client1.hasPendingCalls());
        ASSERT_FALSE(client2.hasPendingCalls());
        ASSERT_TRUE(client3.hasPendingCalls());

        ASSERT_EQ(0, client1.getNumPendingCalls());
        ASSERT_EQ(0, client2.getNumPendingCalls());
        ASSERT_EQ(1, client3.getNumPendingCalls());     // The one addressed to 99 is still waiting

        // Validating
        root_ns_a::StringService::Response expected_response;
        expected_response.string_response = "Request string: Hello world";
        ASSERT_TRUE(handler.match(ResultType::Success, 1, expected_response));

        nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(200));

        ASSERT_FALSE(client1.hasPendingCalls());
        ASSERT_FALSE(client2.hasPendingCalls());
        ASSERT_FALSE(client3.hasPendingCalls());

        ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // Third has timed out :(

        // Validating
        ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 99, root_ns_a::StringService::Response()));

        // Stray request
        ASSERT_LT(0, client3.call(99, request)); // Will timeout!
        ASSERT_TRUE(client3.hasPendingCalls());
        ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());
    }

    // All destroyed - nobody listening
    ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners());
}
Exemplo n.º 8
0
TEST(ServiceClient, ConcurrentCalls)
{
    InterlinkedTestNodesWithSysClock nodes;

    // Type registration
    uavcan::GlobalDataTypeRegistry::instance().reset();
    uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator;

    // Server
    uavcan::ServiceServer<root_ns_a::StringService> server(nodes.a);
    ASSERT_EQ(0, server.start(stringServiceServerCallback));

    // Caller
    typedef uavcan::ServiceCallResult<root_ns_a::StringService> ResultType;
    typedef uavcan::ServiceClient<root_ns_a::StringService,
                                  typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType;
    ServiceCallResultHandler<root_ns_a::StringService> handler;

    /*
     * Initializing
     */
    ClientType client(nodes.b);

    ASSERT_EQ(0, client.getNumPendingCalls());

    client.setCallback(handler.bind());

    ASSERT_EQ(1, nodes.a.getDispatcher().getNumServiceRequestListeners());
    ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners()); // NOT listening!

    ASSERT_FALSE(client.hasPendingCalls());
    ASSERT_EQ(0, client.getNumPendingCalls());

    /*
     * Calling ten requests, the last one will be cancelled
     * Note that there will be non-unique transfer ID values; the client must handle that correctly
     */
    uavcan::ServiceCallID last_call_id;
    for (int i = 0; i < 10; i++)
    {
        std::ostringstream os;
        os << i;
        root_ns_a::StringService::Request request;
        request.string_request = os.str().c_str();
        ASSERT_LT(0, client.call(1, request, last_call_id));
    }

    ASSERT_LT(0, client.call(99, root_ns_a::StringService::Request()));         // Will timeout in 500 ms

    client.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));

    ASSERT_LT(0, client.call(88, root_ns_a::StringService::Request()));         // Will timeout in 100 ms

    ASSERT_TRUE(client.hasPendingCalls());
    ASSERT_EQ(12, client.getNumPendingCalls());

    ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());     // Listening

    /*
     * Cancelling one
     */
    client.cancelCall(last_call_id);

    ASSERT_TRUE(client.hasPendingCalls());
    ASSERT_EQ(11, client.getNumPendingCalls());

    ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());     // Still listening

    /*
     * Spinning
     */
    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(20));

    ASSERT_TRUE(client.hasPendingCalls());
    ASSERT_EQ(2, client.getNumPendingCalls());                                  // Two still pending
    ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());     // Still listening

    /*
     * Validating the ones that didn't timeout
     */
    root_ns_a::StringService::Response last_response;
    for (int i = 0; i < 9; i++)
    {
        std::ostringstream os;
        os << "Request string: " << i;
        last_response.string_response = os.str().c_str();

        ASSERT_FALSE(handler.responses.empty());

        ASSERT_STREQ(last_response.string_response.c_str(), handler.responses.front().string_response.c_str());

        handler.responses.pop();
    }

    ASSERT_TRUE(handler.responses.empty());

    /*
     * Validating the 100 ms timeout
     */
    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(100));

    ASSERT_TRUE(client.hasPendingCalls());
    ASSERT_EQ(1, client.getNumPendingCalls());                                  // One dropped
    ASSERT_EQ(1, nodes.b.getDispatcher().getNumServiceResponseListeners());     // Still listening

    ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 88, root_ns_a::StringService::Response()));

    /*
     * Validating the 500 ms timeout
     */
    nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(500));

    ASSERT_FALSE(client.hasPendingCalls());
    ASSERT_EQ(0, client.getNumPendingCalls());                                  // All finished
    ASSERT_EQ(0, nodes.b.getDispatcher().getNumServiceResponseListeners());     // Not listening

    ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 99, root_ns_a::StringService::Response()));
}