xref: /aosp_15_r20/external/cronet/ipc/ipc_mojo_bootstrap_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ipc/ipc_mojo_bootstrap.h"
6 
7 #include <cstdint>
8 #include <memory>
9 #include <utility>
10 
11 #include "base/run_loop.h"
12 #include "base/task/single_thread_task_runner.h"
13 #include "base/test/task_environment.h"
14 #include "ipc/ipc.mojom.h"
15 #include "ipc/ipc_test_base.h"
16 #include "mojo/core/test/multiprocess_test_helper.h"
17 #include "mojo/public/cpp/bindings/associated_receiver.h"
18 
19 namespace {
20 
21 constexpr int32_t kTestServerPid = 42;
22 constexpr int32_t kTestClientPid = 4242;
23 
24 class Connection {
25  public:
Connection(std::unique_ptr<IPC::MojoBootstrap> bootstrap,int32_t sender_id)26   explicit Connection(std::unique_ptr<IPC::MojoBootstrap> bootstrap,
27                       int32_t sender_id)
28       : bootstrap_(std::move(bootstrap)) {
29     mojo::PendingAssociatedRemote<IPC::mojom::Channel> sender;
30     bootstrap_->Connect(&sender, &receiver_);
31     sender_.Bind(std::move(sender));
32     sender_->SetPeerPid(sender_id);
33 
34     // It's OK to start receiving right away even though `receiver_` isn't
35     // bound, because all of these tests are single-threaded and it will be
36     // bound before any incoming messages can be scheduled for processing.
37     bootstrap_->StartReceiving();
38   }
39 
TakeReceiver(mojo::PendingAssociatedReceiver<IPC::mojom::Channel> * receiver)40   void TakeReceiver(
41       mojo::PendingAssociatedReceiver<IPC::mojom::Channel>* receiver) {
42     *receiver = std::move(receiver_);
43   }
44 
GetSender()45   mojo::AssociatedRemote<IPC::mojom::Channel>& GetSender() { return sender_; }
46 
47  private:
48   mojo::AssociatedRemote<IPC::mojom::Channel> sender_;
49   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver_;
50   std::unique_ptr<IPC::MojoBootstrap> bootstrap_;
51 };
52 
53 class PeerPidReceiver : public IPC::mojom::Channel {
54  public:
55   enum class MessageExpectation {
56     kNotExpected,
57     kExpectedValid,
58     kExpectedInvalid
59   };
60 
PeerPidReceiver(mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver,base::OnceClosure on_peer_pid_set,MessageExpectation message_expectation=MessageExpectation::kNotExpected)61   PeerPidReceiver(
62       mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver,
63       base::OnceClosure on_peer_pid_set,
64       MessageExpectation message_expectation = MessageExpectation::kNotExpected)
65       : receiver_(this, std::move(receiver)),
66         on_peer_pid_set_(std::move(on_peer_pid_set)),
67         message_expectation_(message_expectation) {
68     receiver_.set_disconnect_handler(disconnect_run_loop_.QuitClosure());
69   }
70 
71   PeerPidReceiver(const PeerPidReceiver&) = delete;
72   PeerPidReceiver& operator=(const PeerPidReceiver&) = delete;
73 
~PeerPidReceiver()74   ~PeerPidReceiver() override {
75     bool expected_message =
76         message_expectation_ != MessageExpectation::kNotExpected;
77     EXPECT_EQ(expected_message, received_message_);
78   }
79 
80   // mojom::Channel:
SetPeerPid(int32_t pid)81   void SetPeerPid(int32_t pid) override {
82     peer_pid_ = pid;
83     std::move(on_peer_pid_set_).Run();
84   }
85 
Receive(IPC::MessageView message_view)86   void Receive(IPC::MessageView message_view) override {
87     ASSERT_NE(MessageExpectation::kNotExpected, message_expectation_);
88     received_message_ = true;
89 
90     IPC::Message message(
91         reinterpret_cast<const char*>(message_view.bytes().data()),
92         message_view.bytes().size());
93     bool expected_valid =
94         message_expectation_ == MessageExpectation::kExpectedValid;
95     EXPECT_EQ(expected_valid, message.IsValid());
96   }
97 
GetAssociatedInterface(mojo::GenericPendingAssociatedReceiver receiver)98   void GetAssociatedInterface(
99       mojo::GenericPendingAssociatedReceiver receiver) override {}
100 
peer_pid() const101   int32_t peer_pid() const { return peer_pid_; }
102 
RunUntilDisconnect()103   void RunUntilDisconnect() { disconnect_run_loop_.Run(); }
104 
105  private:
106   mojo::AssociatedReceiver<IPC::mojom::Channel> receiver_;
107   base::OnceClosure on_peer_pid_set_;
108   MessageExpectation message_expectation_;
109   int32_t peer_pid_ = -1;
110   bool received_message_ = false;
111   base::RunLoop disconnect_run_loop_;
112 };
113 
114 class IPCMojoBootstrapTest : public testing::Test {
115  protected:
116   mojo::core::test::MultiprocessTestHelper helper_;
117 };
118 
TEST_F(IPCMojoBootstrapTest,Connect)119 TEST_F(IPCMojoBootstrapTest, Connect) {
120   base::test::SingleThreadTaskEnvironment task_environment;
121   Connection connection(IPC::MojoBootstrap::Create(
122                             helper_.StartChild("IPCMojoBootstrapTestClient"),
123                             IPC::Channel::MODE_SERVER,
124                             base::SingleThreadTaskRunner::GetCurrentDefault(),
125                             base::SingleThreadTaskRunner::GetCurrentDefault()),
126                         kTestServerPid);
127 
128   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
129   connection.TakeReceiver(&receiver);
130 
131   base::RunLoop run_loop;
132   PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
133   run_loop.Run();
134 
135   EXPECT_EQ(kTestClientPid, impl.peer_pid());
136 
137   impl.RunUntilDisconnect();
138   EXPECT_TRUE(helper_.WaitForChildTestShutdown());
139 }
140 
141 // A long running process that connects to us.
MULTIPROCESS_TEST_MAIN_WITH_SETUP(IPCMojoBootstrapTestClientTestChildMain,::mojo::core::test::MultiprocessTestHelper::ChildSetup)142 MULTIPROCESS_TEST_MAIN_WITH_SETUP(
143     IPCMojoBootstrapTestClientTestChildMain,
144     ::mojo::core::test::MultiprocessTestHelper::ChildSetup) {
145   base::test::SingleThreadTaskEnvironment task_environment;
146   Connection connection(
147       IPC::MojoBootstrap::Create(
148           std::move(mojo::core::test::MultiprocessTestHelper::primordial_pipe),
149           IPC::Channel::MODE_CLIENT,
150           base::SingleThreadTaskRunner::GetCurrentDefault(),
151           base::SingleThreadTaskRunner::GetCurrentDefault()),
152       kTestClientPid);
153 
154   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
155   connection.TakeReceiver(&receiver);
156 
157   base::RunLoop run_loop;
158   PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
159   run_loop.Run();
160 
161   EXPECT_EQ(kTestServerPid, impl.peer_pid());
162 
163   return 0;
164 }
165 
TEST_F(IPCMojoBootstrapTest,ReceiveEmptyMessage)166 TEST_F(IPCMojoBootstrapTest, ReceiveEmptyMessage) {
167   base::test::SingleThreadTaskEnvironment task_environment;
168   Connection connection(
169       IPC::MojoBootstrap::Create(
170           helper_.StartChild("IPCMojoBootstrapTestEmptyMessage"),
171           IPC::Channel::MODE_SERVER,
172           base::SingleThreadTaskRunner::GetCurrentDefault(),
173           base::SingleThreadTaskRunner::GetCurrentDefault()),
174       kTestServerPid);
175 
176   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
177   connection.TakeReceiver(&receiver);
178 
179   base::RunLoop run_loop;
180   PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure(),
181                        PeerPidReceiver::MessageExpectation::kExpectedInvalid);
182   run_loop.Run();
183 
184   // Wait for the Channel to be disconnected so we can reasonably assert that
185   // the child's empty message must have been received before we pass the test.
186   impl.RunUntilDisconnect();
187 
188   EXPECT_TRUE(helper_.WaitForChildTestShutdown());
189 }
190 
191 // A long running process that connects to us.
MULTIPROCESS_TEST_MAIN_WITH_SETUP(IPCMojoBootstrapTestEmptyMessageTestChildMain,::mojo::core::test::MultiprocessTestHelper::ChildSetup)192 MULTIPROCESS_TEST_MAIN_WITH_SETUP(
193     IPCMojoBootstrapTestEmptyMessageTestChildMain,
194     ::mojo::core::test::MultiprocessTestHelper::ChildSetup) {
195   base::test::SingleThreadTaskEnvironment task_environment;
196   Connection connection(
197       IPC::MojoBootstrap::Create(
198           std::move(mojo::core::test::MultiprocessTestHelper::primordial_pipe),
199           IPC::Channel::MODE_CLIENT,
200           base::SingleThreadTaskRunner::GetCurrentDefault(),
201           base::SingleThreadTaskRunner::GetCurrentDefault()),
202       kTestClientPid);
203 
204   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
205   connection.TakeReceiver(&receiver);
206   auto& sender = connection.GetSender();
207 
208   uint8_t data = 0;
209   sender->Receive(
210       IPC::MessageView(base::make_span(&data, 0u), std::nullopt /* handles */));
211 
212   base::RunLoop run_loop;
213   PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
214   run_loop.Run();
215 
216   return 0;
217 }
218 
219 }  // namespace
220