|
11 | 11 | #include "tracking_memory_resource.hpp" |
12 | 12 | #include "transport/scattered_buffer_storage_mock.hpp" |
13 | 13 | #include "transport/svc_sessions_mock.hpp" |
| 14 | +#include "transport/transfer_id_map_mock.hpp" |
14 | 15 | #include "transport/transport_gtest_helpers.hpp" |
15 | 16 | #include "transport/transport_mock.hpp" |
16 | 17 | #include "virtual_time_scheduler.hpp" |
|
23 | 24 | #include <libcyphal/presentation/response_promise.hpp> |
24 | 25 | #include <libcyphal/transport/errors.hpp> |
25 | 26 | #include <libcyphal/transport/svc_sessions.hpp> |
| 27 | +#include <libcyphal/transport/transfer_id_map.hpp> |
26 | 28 | #include <libcyphal/transport/types.hpp> |
27 | 29 | #include <libcyphal/types.hpp> |
28 | 30 |
|
@@ -789,7 +791,7 @@ TEST_F(TestClient, raw_request_response_failures) |
789 | 791 | State state{mr_, transport_mock_, rx_params}; |
790 | 792 |
|
791 | 793 | // Emulate that transport supports only 2 concurrent transfers by having module equal to 2^1. |
792 | | - // This will make the client fail to make more than 2 request. |
| 794 | + // This will make the client fail to make more than 2 requests. |
793 | 795 | EXPECT_CALL(transport_mock_, getProtocolParams()).WillRepeatedly(Return(ProtocolParams{2, 0, 0})); |
794 | 796 |
|
795 | 797 | Presentation presentation{mr_, scheduler_, transport_mock_}; |
@@ -829,6 +831,84 @@ TEST_F(TestClient, raw_request_response_failures) |
829 | 831 | scheduler_.spinFor(10s); |
830 | 832 | } |
831 | 833 |
|
| 834 | +TEST_F(TestClient, multiple_clients_with_transfer_id_map) |
| 835 | +{ |
| 836 | + using SvcResPromise = ResponsePromise<void>; |
| 837 | + using SessionSpec = ITransferIdMap::SessionSpec; |
| 838 | + |
| 839 | + StrictMock<TransferIdMapMock> transfer_id_map_mock; |
| 840 | + |
| 841 | + constexpr ResponseRxParams rx_params_n31{4, 147, 0x31}; |
| 842 | + constexpr ResponseRxParams rx_params_n32{4, 147, 0x32}; |
| 843 | + |
| 844 | + State state_31{mr_, transport_mock_, rx_params_n31}; |
| 845 | + State state_32{mr_, transport_mock_, rx_params_n32}; |
| 846 | + |
| 847 | + Presentation presentation{mr_, scheduler_, transport_mock_}; |
| 848 | + presentation.setTransferIdMap(&transfer_id_map_mock); |
| 849 | + |
| 850 | + EXPECT_CALL(transfer_id_map_mock, getIdFor(SessionSpec{rx_params_n31.service_id, rx_params_n31.server_node_id})) |
| 851 | + .WillOnce(Return(0x310)); |
| 852 | + EXPECT_CALL(transfer_id_map_mock, getIdFor(SessionSpec{rx_params_n32.service_id, rx_params_n32.server_node_id})) |
| 853 | + .WillOnce(Return(0x320)); |
| 854 | + |
| 855 | + auto maybe_client_n31 = presentation.makeClient( // |
| 856 | + rx_params_n31.server_node_id, |
| 857 | + rx_params_n31.service_id, |
| 858 | + rx_params_n31.extent_bytes); |
| 859 | + ASSERT_THAT(maybe_client_n31, VariantWith<RawServiceClient>(_)); |
| 860 | + cetl::optional<RawServiceClient> client_n31 = cetl::get<RawServiceClient>(std::move(maybe_client_n31)); |
| 861 | + |
| 862 | + auto maybe_client_n32 = presentation.makeClient( // |
| 863 | + rx_params_n32.server_node_id, |
| 864 | + rx_params_n32.service_id, |
| 865 | + rx_params_n32.extent_bytes); |
| 866 | + ASSERT_THAT(maybe_client_n32, VariantWith<RawServiceClient>(_)); |
| 867 | + cetl::optional<RawServiceClient> client_n32 = cetl::get<RawServiceClient>(std::move(maybe_client_n32)); |
| 868 | + |
| 869 | + scheduler_.scheduleAt(1s, [&](const auto&) { |
| 870 | + // |
| 871 | + EXPECT_CALL(state_31.req_tx_session_mock_, send(_, _)) // |
| 872 | + .WillOnce(Invoke([now = now()](const auto& metadata, const auto) { |
| 873 | + // |
| 874 | + EXPECT_THAT(metadata.base.transfer_id, 0x310); |
| 875 | + return cetl::nullopt; |
| 876 | + })); |
| 877 | + |
| 878 | + const auto maybe_promise = client_n31->request(now() + 100ms, {}, now() + 2s); |
| 879 | + EXPECT_THAT(maybe_promise, VariantWith<SvcResPromise>(_)); |
| 880 | + }); |
| 881 | + scheduler_.scheduleAt(2s, [&](const auto&) { |
| 882 | + // |
| 883 | + EXPECT_CALL(state_32.req_tx_session_mock_, send(_, _)) // |
| 884 | + .WillOnce(Invoke([now = now()](const auto& metadata, const auto) { |
| 885 | + // |
| 886 | + EXPECT_THAT(metadata.base.transfer_id, 0x320); |
| 887 | + return cetl::nullopt; |
| 888 | + })); |
| 889 | + |
| 890 | + const auto maybe_promise = client_n32->request(now() + 100ms, {}, now() + 2s); |
| 891 | + EXPECT_THAT(maybe_promise, VariantWith<SvcResPromise>(_)); |
| 892 | + }); |
| 893 | + scheduler_.scheduleAt(8s, [&](const auto&) { |
| 894 | + // |
| 895 | + EXPECT_CALL(transfer_id_map_mock, |
| 896 | + setIdFor(SessionSpec{rx_params_n32.service_id, rx_params_n32.server_node_id}, 0x320 + 1)) |
| 897 | + .WillOnce(Return()); |
| 898 | + |
| 899 | + client_n32.reset(); |
| 900 | + }); |
| 901 | + scheduler_.scheduleAt(9s, [&](const auto&) { |
| 902 | + // |
| 903 | + EXPECT_CALL(transfer_id_map_mock, |
| 904 | + setIdFor(SessionSpec{rx_params_n31.service_id, rx_params_n31.server_node_id}, 0x310 + 1)) |
| 905 | + .WillOnce(Return()); |
| 906 | + |
| 907 | + client_n31.reset(); |
| 908 | + }); |
| 909 | + scheduler_.spinFor(10s); |
| 910 | +} |
| 911 | + |
832 | 912 | // NOLINTEND(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers, *-function-cognitive-complexity) |
833 | 913 |
|
834 | 914 | } // namespace |
0 commit comments