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