1 // Copyright 2019 The Chromium Authors. All rights reserved.
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 "third_party/blink/public/common/messaging/message_port_descriptor.h"
6 
7 #include "base/test/gtest_util.h"
8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace blink {
12 
13 namespace {
14 
15 class LenientMockInstrumentationDelegate
16     : public MessagePortDescriptor::InstrumentationDelegate {
17  public:
LenientMockInstrumentationDelegate()18   LenientMockInstrumentationDelegate() {
19     MessagePortDescriptor::SetInstrumentationDelegate(this);
20   }
21 
~LenientMockInstrumentationDelegate()22   ~LenientMockInstrumentationDelegate() override {
23     MessagePortDescriptor::SetInstrumentationDelegate(nullptr);
24   }
25 
26   MOCK_METHOD2(NotifyMessagePortPairCreated,
27                void(const base::UnguessableToken& port0_id,
28                     const base::UnguessableToken& port1_id));
29 
30   MOCK_METHOD3(NotifyMessagePortAttached,
31                void(const base::UnguessableToken& port_id,
32                     uint64_t sequence_number,
33                     const base::UnguessableToken& execution_context_id));
34 
35   MOCK_METHOD2(NotifyMessagePortAttachedToEmbedder,
36                void(const base::UnguessableToken& port_id,
37                     uint64_t sequence_number));
38 
39   MOCK_METHOD2(NotifyMessagePortDetached,
40                void(const base::UnguessableToken& port_id,
41                     uint64_t sequence_number));
42 
43   MOCK_METHOD2(NotifyMessagePortDestroyed,
44                void(const base::UnguessableToken& port_id,
45                     uint64_t sequence_number));
46 };
47 
48 using MockInstrumentationDelegate =
49     testing::StrictMock<LenientMockInstrumentationDelegate>;
50 
51 using testing::_;
52 using testing::Invoke;
53 
54 }  // namespace
55 
56 class MessagePortDescriptorTestHelper {
57  public:
Init(MessagePortDescriptor * port,mojo::ScopedMessagePipeHandle handle,base::UnguessableToken id,uint64_t sequence_number)58   static void Init(MessagePortDescriptor* port,
59                    mojo::ScopedMessagePipeHandle handle,
60                    base::UnguessableToken id,
61                    uint64_t sequence_number) {
62     return port->Init(std::move(handle), id, sequence_number);
63   }
64 
TakeHandle(MessagePortDescriptor * port)65   static mojo::ScopedMessagePipeHandle TakeHandle(MessagePortDescriptor* port) {
66     return port->TakeHandle();
67   }
68 
TakeId(MessagePortDescriptor * port)69   static base::UnguessableToken TakeId(MessagePortDescriptor* port) {
70     return port->TakeId();
71   }
72 
TakeSequenceNumber(MessagePortDescriptor * port)73   static uint64_t TakeSequenceNumber(MessagePortDescriptor* port) {
74     return port->TakeSequenceNumber();
75   }
76 
TakeHandleToEntangle(MessagePortDescriptor * port,const base::UnguessableToken & execution_context_id)77   static mojo::ScopedMessagePipeHandle TakeHandleToEntangle(
78       MessagePortDescriptor* port,
79       const base::UnguessableToken& execution_context_id) {
80     return port->TakeHandleToEntangle(execution_context_id);
81   }
82 
GiveDisentangledHandle(MessagePortDescriptor * port,mojo::ScopedMessagePipeHandle handle)83   static void GiveDisentangledHandle(MessagePortDescriptor* port,
84                                      mojo::ScopedMessagePipeHandle handle) {
85     return port->GiveDisentangledHandle(std::move(handle));
86   }
87 };
88 
TEST(MessagePortDescriptorTest,InstrumentationAndSerializationWorks)89 TEST(MessagePortDescriptorTest, InstrumentationAndSerializationWorks) {
90   MockInstrumentationDelegate delegate;
91 
92   // A small struct for holding information gleaned about ports during their
93   // creation event. Allows verifying that other events are appropriately
94   // sequenced.
95   struct {
96     base::UnguessableToken token0;
97     base::UnguessableToken token1;
98     uint64_t seq0 = 1;
99     uint64_t seq1 = 1;
100   } created_data;
101 
102   // Create a message handle descriptor pair and expect a notification.
103   EXPECT_CALL(delegate, NotifyMessagePortPairCreated(_, _))
104       .WillOnce(Invoke([&created_data](const base::UnguessableToken& port0_id,
105                                        const base::UnguessableToken& port1_id) {
106         created_data.token0 = port0_id;
107         created_data.token1 = port1_id;
108       }));
109   MessagePortDescriptorPair pair;
110 
111   MessagePortDescriptor port0;
112   MessagePortDescriptor port1;
113   EXPECT_FALSE(port0.IsValid());
114   EXPECT_FALSE(port1.IsValid());
115   EXPECT_FALSE(port0.IsEntangled());
116   EXPECT_FALSE(port1.IsEntangled());
117   EXPECT_TRUE(port0.IsDefault());
118   EXPECT_TRUE(port1.IsDefault());
119   port0 = pair.TakePort0();
120   port1 = pair.TakePort1();
121   EXPECT_TRUE(port0.IsValid());
122   EXPECT_TRUE(port1.IsValid());
123   EXPECT_FALSE(port0.IsEntangled());
124   EXPECT_FALSE(port1.IsEntangled());
125   EXPECT_FALSE(port0.IsDefault());
126   EXPECT_FALSE(port1.IsDefault());
127 
128   // Expect that the data received at creation matches the actual ports.
129   EXPECT_EQ(created_data.token0, port0.id());
130   EXPECT_EQ(created_data.seq0, port0.sequence_number());
131   EXPECT_EQ(created_data.token1, port1.id());
132   EXPECT_EQ(created_data.seq1, port1.sequence_number());
133 
134   // Simulate that a handle is attached by taking the pipe handle.
135   base::UnguessableToken dummy_ec = base::UnguessableToken::Create();
136   EXPECT_CALL(delegate,
137               NotifyMessagePortAttached(created_data.token0,
138                                         created_data.seq0++, dummy_ec));
139   auto handle0 =
140       MessagePortDescriptorTestHelper::TakeHandleToEntangle(&port0, dummy_ec);
141   EXPECT_TRUE(port0.IsValid());
142   EXPECT_TRUE(port0.IsEntangled());
143   EXPECT_FALSE(port0.IsDefault());
144 
145   // Simulate that the handle is detached by giving the pipe handle back.
146   EXPECT_CALL(delegate, NotifyMessagePortDetached(created_data.token0,
147                                                   created_data.seq0++));
148   MessagePortDescriptorTestHelper::GiveDisentangledHandle(&port0,
149                                                           std::move(handle0));
150   EXPECT_TRUE(port0.IsValid());
151   EXPECT_FALSE(port0.IsEntangled());
152   EXPECT_FALSE(port0.IsDefault());
153 
154   // Tear down a handle explicitly.
155   EXPECT_CALL(delegate, NotifyMessagePortDestroyed(created_data.token1,
156                                                    created_data.seq1++));
157   port1.Reset();
158 
159   // And leave the other handle to be torn down in the destructor.
160   EXPECT_CALL(delegate, NotifyMessagePortDestroyed(created_data.token0,
161                                                    created_data.seq0++));
162 }
163 
TEST(MessagePortDescriptorTest,InvalidUsageDeathTest)164 TEST(MessagePortDescriptorTest, InvalidUsageDeathTest) {
165   static MessagePortDescriptor::InstrumentationDelegate* kDummyDelegate1 =
166       reinterpret_cast<MessagePortDescriptor::InstrumentationDelegate*>(
167           0xBAADF00D);
168   static MessagePortDescriptor::InstrumentationDelegate* kDummyDelegate2 =
169       reinterpret_cast<MessagePortDescriptor::InstrumentationDelegate*>(
170           0xDEADBEEF);
171   EXPECT_DCHECK_DEATH(
172       MessagePortDescriptor::SetInstrumentationDelegate(nullptr));
173   MessagePortDescriptor::SetInstrumentationDelegate(kDummyDelegate1);
174   // Setting the same or another delegate should explode.
175   EXPECT_DCHECK_DEATH(
176       MessagePortDescriptor::SetInstrumentationDelegate(kDummyDelegate1));
177   EXPECT_DCHECK_DEATH(
178       MessagePortDescriptor::SetInstrumentationDelegate(kDummyDelegate2));
179   // Unset the dummy delegate we installed so we don't receive notifications in
180   // the rest of the test.
181   MessagePortDescriptor::SetInstrumentationDelegate(nullptr);
182 
183   // Trying to take properties of a default port descriptor should explode.
184   MessagePortDescriptor port0;
185   EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::TakeHandle(&port0));
186   EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::TakeId(&port0));
187   EXPECT_DCHECK_DEATH(
188       MessagePortDescriptorTestHelper::TakeSequenceNumber(&port0));
189 
190   MessagePortDescriptorPair pair;
191   port0 = pair.TakePort0();
192   MessagePortDescriptor port1 = pair.TakePort1();
193 
194   {
195     // Dismantle the port as if for serialization.
196     auto handle = MessagePortDescriptorTestHelper::TakeHandle(&port0);
197     auto id = MessagePortDescriptorTestHelper::TakeId(&port0);
198     auto sequence_number =
199         MessagePortDescriptorTestHelper::TakeSequenceNumber(&port0);
200 
201     // Reserializing with inconsistent state should explode.
202 
203     // First try with any 1 of the 3 fields being invalid.
204     EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::Init(
205         &port0, mojo::ScopedMessagePipeHandle(), id, sequence_number));
206     EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::Init(
207         &port0, std::move(handle), base::UnguessableToken::Null(),
208         sequence_number));
209     EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::Init(
210         &port0, std::move(handle), id, 0));
211 
212     // Next try with any 2 of the 3 fields being invalid.
213     EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::Init(
214         &port0, std::move(handle), base::UnguessableToken::Null(), 0));
215     EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::Init(
216         &port0, mojo::ScopedMessagePipeHandle(), id, 0));
217     EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::Init(
218         &port0, mojo::ScopedMessagePipeHandle(), base::UnguessableToken::Null(),
219         sequence_number));
220 
221     // Restoring the port with default state should work (all 3 fields invalid).
222     MessagePortDescriptorTestHelper::Init(&port0,
223                                           mojo::ScopedMessagePipeHandle(),
224                                           base::UnguessableToken::Null(), 0);
225     EXPECT_TRUE(port0.IsDefault());
226 
227     // Restoring the port with full state should work (all 3 fields valid).
228     MessagePortDescriptorTestHelper::Init(&port0, std::move(handle), id,
229                                           sequence_number);
230   }
231 
232   // Entangle the port.
233   base::UnguessableToken dummy_ec = base::UnguessableToken::Create();
234   auto handle0 =
235       MessagePortDescriptorTestHelper::TakeHandleToEntangle(&port0, dummy_ec);
236 
237   // Trying to entangle a second time should explode.
238   EXPECT_DCHECK_DEATH(
239       MessagePortDescriptorTestHelper::TakeHandleToEntangle(&port0, dummy_ec));
240 
241   // Destroying a port descriptor that has been entangled should explode. The
242   // handle needs to be given back to the descriptor before its death, ensuring
243   // descriptors remain fully accounted for over their entire lifecycle.
244   EXPECT_DCHECK_DEATH(port0.Reset());
245 
246   // Trying to assign while the handle is entangled should explode, as it
247   // amounts to destroying the existing descriptor.
248   EXPECT_DCHECK_DEATH(port0 = MessagePortDescriptor());
249 
250   // Trying to disentangle with an empty port should explode.
251   mojo::ScopedMessagePipeHandle handle1;
252   EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::GiveDisentangledHandle(
253       &port0, std::move(handle1)));
254 
255   // Trying to disentangle with the wrong port should explode.
256   handle1 =
257       MessagePortDescriptorTestHelper::TakeHandleToEntangle(&port1, dummy_ec);
258   EXPECT_DCHECK_DEATH(MessagePortDescriptorTestHelper::GiveDisentangledHandle(
259       &port0, std::move(handle1)));
260 
261   // Disentangle the ports properly.
262   MessagePortDescriptorTestHelper::GiveDisentangledHandle(&port0,
263                                                           std::move(handle0));
264   MessagePortDescriptorTestHelper::GiveDisentangledHandle(&port1,
265                                                           std::move(handle1));
266 }
267 
268 }  // namespace blink
269