1fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <uds/client_channel.h> 2fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 3fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <sys/socket.h> 4fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 5fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <algorithm> 6fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <limits> 7fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <random> 8fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <thread> 9fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 10fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <gmock/gmock.h> 11fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <gtest/gtest.h> 12fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 13fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <pdx/client.h> 14fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <pdx/rpc/remote_method.h> 15fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <pdx/service.h> 165a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko#include <pdx/service_dispatcher.h> 17fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 18fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <uds/client_channel_factory.h> 19fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko#include <uds/service_endpoint.h> 20fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 21fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing testing::Return; 22fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing testing::_; 23fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 24fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::ClientBase; 25fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::LocalChannelHandle; 26fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::LocalHandle; 27fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::Message; 28fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::ServiceBase; 29fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::ServiceDispatcher; 30fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::Status; 31fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::rpc::DispatchRemoteMethod; 32fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::uds::ClientChannel; 33fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::uds::ClientChannelFactory; 34fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkousing android::pdx::uds::Endpoint; 35fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 36fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkonamespace { 37fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 38fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkostruct TestProtocol { 39fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko using DataType = int8_t; 40fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko enum { 41fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko kOpSum = 0, 42fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko }; 43fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko PDX_REMOTE_METHOD(Sum, kOpSum, int64_t(const std::vector<DataType>&)); 44fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko}; 45fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 46fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkoclass TestService : public ServiceBase<TestService> { 47fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko public: 48fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko TestService(std::unique_ptr<Endpoint> endpoint) 49fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko : ServiceBase{"TestService", std::move(endpoint)} {} 50fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 51fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko Status<void> HandleMessage(Message& message) override { 52fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko switch (message.GetOp()) { 53fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko case TestProtocol::kOpSum: 54fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko DispatchRemoteMethod<TestProtocol::Sum>(*this, &TestService::OnSum, 55fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko message); 56fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko return {}; 57fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 58fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko default: 59fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko return Service::HandleMessage(message); 60fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 61fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 62fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 63fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko int64_t OnSum(Message& /*message*/, 64fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko const std::vector<TestProtocol::DataType>& data) { 65fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko return std::accumulate(data.begin(), data.end(), int64_t{0}); 66fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 67fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko}; 68fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 69fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkoclass TestClient : public ClientBase<TestClient> { 70fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko public: 71fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko using ClientBase::ClientBase; 72fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 73fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko int64_t Sum(const std::vector<TestProtocol::DataType>& data) { 74fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko auto status = InvokeRemoteMethod<TestProtocol::Sum>(data); 75fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko return status ? status.get() : -1; 76fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 77fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko}; 78fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 79fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkoclass TestServiceRunner { 80fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko public: 81fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko TestServiceRunner(LocalHandle channel_socket) { 82fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko auto endpoint = Endpoint::CreateFromSocketFd(LocalHandle{}); 83fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko endpoint->RegisterNewChannelForTests(std::move(channel_socket)); 84fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko service_ = TestService::Create(std::move(endpoint)); 855a244ed36c8e45fd95b89ff916caf083fb182ec1Alex Vakulenko dispatcher_ = ServiceDispatcher::Create(); 86fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko dispatcher_->AddService(service_); 87fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko dispatch_thread_ = std::thread( 88fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::bind(&ServiceDispatcher::EnterDispatchLoop, dispatcher_.get())); 89fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 90fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 91fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko ~TestServiceRunner() { 92fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko dispatcher_->SetCanceled(true); 93fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko dispatch_thread_.join(); 94fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko dispatcher_->RemoveService(service_); 95fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 96fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 97fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko private: 98fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::shared_ptr<TestService> service_; 99fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::unique_ptr<ServiceDispatcher> dispatcher_; 100fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::thread dispatch_thread_; 101fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko}; 102fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 103fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenkoclass ClientChannelTest : public testing::Test { 104fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko public: 105fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko void SetUp() override { 106fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko int channel_sockets[2] = {}; 107fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko ASSERT_EQ( 108fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, channel_sockets)); 109fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko LocalHandle service_channel{channel_sockets[0]}; 110fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko LocalHandle client_channel{channel_sockets[1]}; 111fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 112fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko service_runner_.reset(new TestServiceRunner{std::move(service_channel)}); 113fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko auto factory = ClientChannelFactory::Create(std::move(client_channel)); 114fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko auto status = factory->Connect(android::pdx::Client::kInfiniteTimeout); 115fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko ASSERT_TRUE(status); 116fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko client_ = TestClient::Create(status.take()); 117fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 118fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 119fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko void TearDown() override { 120fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko service_runner_.reset(); 121fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko client_.reset(); 122fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 123fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 124fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko protected: 125fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::unique_ptr<TestServiceRunner> service_runner_; 126fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::shared_ptr<TestClient> client_; 127fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko}; 128fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 129fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex VakulenkoTEST_F(ClientChannelTest, MultithreadedClient) { 130fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko constexpr int kNumTestThreads = 8; 131fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko constexpr size_t kDataSize = 1000; // Try to keep RPC buffer size below 4K. 132fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 133fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::random_device rd; 134fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::mt19937 gen{rd()}; 135fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::uniform_int_distribution<TestProtocol::DataType> dist{ 136fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::numeric_limits<TestProtocol::DataType>::min(), 137fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::numeric_limits<TestProtocol::DataType>::max()}; 138fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 139fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko auto worker = [](std::shared_ptr<TestClient> client, 140fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::vector<TestProtocol::DataType> data) { 141fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko constexpr int kMaxIterations = 500; 142fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko int64_t expected = std::accumulate(data.begin(), data.end(), int64_t{0}); 143fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko for (int i = 0; i < kMaxIterations; i++) { 144fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko ASSERT_EQ(expected, client->Sum(data)); 145fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 146fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko }; 147fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 148fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko // Start client threads. 149fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::vector<TestProtocol::DataType> data; 150fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko data.resize(kDataSize); 151fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::vector<std::thread> threads; 152fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko for (int i = 0; i < kNumTestThreads; i++) { 153fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko std::generate(data.begin(), data.end(), 154fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko [&dist, &gen]() { return dist(gen); }); 155fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko threads.emplace_back(worker, client_, data); 156fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko } 157fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 158fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko // Wait for threads to finish. 159fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko for (auto& thread : threads) 160fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko thread.join(); 161fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko} 162fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko 163fd22b3e5ad1aae1fc3de54801f33466db3c9b3feAlex Vakulenko} // namespace 164