1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "chrome/common/ipc_message.h"
8 #include "gtest/gtest.h"
10 #include "mozilla/gtest/MozAssertions.h"
11 #include "mozilla/ipc/DataPipe.h"
12 #include "nsIAsyncInputStream.h"
13 #include "nsIAsyncOutputStream.h"
14 #include "nsNetUtil.h"
15 #include "nsStreamUtils.h"
17 namespace mozilla::ipc
{
21 struct InputStreamCallback
: public nsIInputStreamCallback
{
23 NS_DECL_THREADSAFE_ISUPPORTS
25 explicit InputStreamCallback(
26 std::function
<nsresult(nsIAsyncInputStream
*)> aFunc
= nullptr)
27 : mFunc(std::move(aFunc
)) {}
29 NS_IMETHOD
OnInputStreamReady(nsIAsyncInputStream
* aStream
) override
{
30 MOZ_ALWAYS_FALSE(mCalled
.exchange(true));
31 return mFunc
? mFunc(aStream
) : NS_OK
;
34 bool Called() const { return mCalled
; }
37 virtual ~InputStreamCallback() = default;
39 std::atomic
<bool> mCalled
= false;
40 std::function
<nsresult(nsIAsyncInputStream
*)> mFunc
;
43 NS_IMPL_ISUPPORTS(InputStreamCallback
, nsIInputStreamCallback
)
45 struct OutputStreamCallback
: public nsIOutputStreamCallback
{
47 NS_DECL_THREADSAFE_ISUPPORTS
49 explicit OutputStreamCallback(
50 std::function
<nsresult(nsIAsyncOutputStream
*)> aFunc
= nullptr)
51 : mFunc(std::move(aFunc
)) {}
53 NS_IMETHOD
OnOutputStreamReady(nsIAsyncOutputStream
* aStream
) override
{
54 MOZ_ALWAYS_FALSE(mCalled
.exchange(true));
55 return mFunc
? mFunc(aStream
) : NS_OK
;
58 bool Called() const { return mCalled
; }
61 virtual ~OutputStreamCallback() = default;
63 std::atomic
<bool> mCalled
= false;
64 std::function
<nsresult(nsIAsyncOutputStream
*)> mFunc
;
67 NS_IMPL_ISUPPORTS(OutputStreamCallback
, nsIOutputStreamCallback
)
69 // Populate an array with the given number of bytes. Data is lorem ipsum
70 // random text, but deterministic across multiple calls.
71 void CreateData(uint32_t aNumBytes
, nsCString
& aDataOut
) {
72 static const char data
[] =
73 "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec egestas "
74 "purus eu condimentum iaculis. In accumsan leo eget odio porttitor, non "
75 "rhoncus nulla vestibulum. Etiam lacinia consectetur nisl nec "
76 "sollicitudin. Sed fringilla accumsan diam, pulvinar varius massa. Duis "
77 "mollis dignissim felis, eget tempus nisi tristique ut. Fusce euismod, "
78 "lectus non lacinia tempor, tellus diam suscipit quam, eget hendrerit "
79 "lacus nunc fringilla ante. Sed ultrices massa vitae risus molestie, ut "
80 "finibus quam laoreet nullam.";
81 static const uint32_t dataLength
= sizeof(data
) - 1;
83 aDataOut
.SetCapacity(aNumBytes
);
85 while (aNumBytes
> 0) {
86 uint32_t amount
= std::min(dataLength
, aNumBytes
);
87 aDataOut
.Append(data
, amount
);
92 // Synchronously consume the given input stream and validate the resulting data
93 // against the given string of expected values.
94 void ConsumeAndValidateStream(nsIInputStream
* aStream
,
95 const nsACString
& aExpectedData
) {
96 nsAutoCString outputData
;
97 nsresult rv
= NS_ConsumeStream(aStream
, UINT32_MAX
, outputData
);
98 ASSERT_NS_SUCCEEDED(rv
);
99 ASSERT_EQ(aExpectedData
.Length(), outputData
.Length());
100 ASSERT_TRUE(aExpectedData
.Equals(outputData
));
105 TEST(DataPipe
, SegmentedReadWrite
)
107 RefPtr
<DataPipeReceiver
> reader
;
108 RefPtr
<DataPipeSender
> writer
;
111 NewDataPipe(1024, getter_AddRefs(writer
), getter_AddRefs(reader
));
112 ASSERT_NS_SUCCEEDED(rv
);
114 nsCString inputData1
;
115 CreateData(512, inputData1
);
117 uint32_t numWritten
= 0;
118 rv
= writer
->Write(inputData1
.BeginReading(), inputData1
.Length(),
120 ASSERT_NS_SUCCEEDED(rv
);
121 EXPECT_EQ(numWritten
, 512u);
123 uint64_t available
= 0;
124 rv
= reader
->Available(&available
);
125 EXPECT_EQ(available
, 512u);
126 ConsumeAndValidateStream(reader
, inputData1
);
128 nsCString inputData2
;
129 CreateData(1024, inputData2
);
131 rv
= writer
->Write(inputData2
.BeginReading(), inputData2
.Length(),
133 ASSERT_NS_SUCCEEDED(rv
);
134 EXPECT_EQ(numWritten
, 1024u);
136 rv
= reader
->Available(&available
);
137 EXPECT_EQ(available
, 1024u);
138 ConsumeAndValidateStream(reader
, inputData2
);
141 TEST(DataPipe
, SegmentedPartialRead
)
143 RefPtr
<DataPipeReceiver
> reader
;
144 RefPtr
<DataPipeSender
> writer
;
147 NewDataPipe(1024, getter_AddRefs(writer
), getter_AddRefs(reader
));
148 ASSERT_NS_SUCCEEDED(rv
);
150 nsCString inputData1
;
151 CreateData(512, inputData1
);
153 uint32_t numWritten
= 0;
154 rv
= writer
->Write(inputData1
.BeginReading(), inputData1
.Length(),
156 ASSERT_NS_SUCCEEDED(rv
);
157 EXPECT_EQ(numWritten
, 512u);
159 uint64_t available
= 0;
160 rv
= reader
->Available(&available
);
161 EXPECT_EQ(available
, 512u);
162 ConsumeAndValidateStream(reader
, inputData1
);
164 nsCString inputData2
;
165 CreateData(1024, inputData2
);
167 rv
= writer
->Write(inputData2
.BeginReading(), inputData2
.Length(),
169 ASSERT_NS_SUCCEEDED(rv
);
170 EXPECT_EQ(numWritten
, 1024u);
172 rv
= reader
->Available(&available
);
173 EXPECT_EQ(available
, 1024u);
175 nsAutoCString outputData
;
176 rv
= NS_ReadInputStreamToString(reader
, outputData
, 768);
177 ASSERT_NS_SUCCEEDED(rv
);
178 ASSERT_EQ(768u, outputData
.Length());
179 ASSERT_TRUE(Substring(inputData2
, 0, 768).Equals(outputData
));
181 rv
= reader
->Available(&available
);
182 EXPECT_EQ(available
, 256u);
184 nsAutoCString outputData2
;
185 rv
= NS_ReadInputStreamToString(reader
, outputData2
, 256);
186 ASSERT_NS_SUCCEEDED(rv
);
187 ASSERT_EQ(256u, outputData2
.Length());
188 ASSERT_TRUE(Substring(inputData2
, 768).Equals(outputData2
));
191 TEST(DataPipe
, Write_AsyncWait
)
193 RefPtr
<DataPipeReceiver
> reader
;
194 RefPtr
<DataPipeSender
> writer
;
196 const uint32_t segmentSize
= 1024;
199 NewDataPipe(segmentSize
, getter_AddRefs(writer
), getter_AddRefs(reader
));
200 ASSERT_NS_SUCCEEDED(rv
);
203 CreateData(segmentSize
, inputData
);
205 uint32_t numWritten
= 0;
206 rv
= writer
->Write(inputData
.BeginReading(), inputData
.Length(), &numWritten
);
207 ASSERT_NS_SUCCEEDED(rv
);
208 EXPECT_EQ(numWritten
, segmentSize
);
210 rv
= writer
->Write(inputData
.BeginReading(), inputData
.Length(), &numWritten
);
211 ASSERT_EQ(NS_BASE_STREAM_WOULD_BLOCK
, rv
);
213 RefPtr
<OutputStreamCallback
> cb
= new OutputStreamCallback();
215 rv
= writer
->AsyncWait(cb
, 0, 0, GetCurrentSerialEventTarget());
216 ASSERT_NS_SUCCEEDED(rv
);
218 NS_ProcessPendingEvents(nullptr);
220 ASSERT_FALSE(cb
->Called());
222 ConsumeAndValidateStream(reader
, inputData
);
224 ASSERT_FALSE(cb
->Called());
226 NS_ProcessPendingEvents(nullptr);
228 ASSERT_TRUE(cb
->Called());
231 TEST(DataPipe
, Read_AsyncWait
)
233 RefPtr
<DataPipeReceiver
> reader
;
234 RefPtr
<DataPipeSender
> writer
;
236 const uint32_t segmentSize
= 1024;
239 NewDataPipe(segmentSize
, getter_AddRefs(writer
), getter_AddRefs(reader
));
240 ASSERT_NS_SUCCEEDED(rv
);
243 CreateData(segmentSize
, inputData
);
245 RefPtr
<InputStreamCallback
> cb
= new InputStreamCallback();
247 rv
= reader
->AsyncWait(cb
, 0, 0, GetCurrentSerialEventTarget());
248 ASSERT_NS_SUCCEEDED(rv
);
250 NS_ProcessPendingEvents(nullptr);
252 ASSERT_FALSE(cb
->Called());
254 uint32_t numWritten
= 0;
255 rv
= writer
->Write(inputData
.BeginReading(), inputData
.Length(), &numWritten
);
256 ASSERT_NS_SUCCEEDED(rv
);
258 ASSERT_FALSE(cb
->Called());
260 NS_ProcessPendingEvents(nullptr);
262 ASSERT_TRUE(cb
->Called());
264 ConsumeAndValidateStream(reader
, inputData
);
267 TEST(DataPipe
, Write_AsyncWait_Cancel
)
269 RefPtr
<DataPipeReceiver
> reader
;
270 RefPtr
<DataPipeSender
> writer
;
272 const uint32_t segmentSize
= 1024;
275 NewDataPipe(segmentSize
, getter_AddRefs(writer
), getter_AddRefs(reader
));
276 ASSERT_NS_SUCCEEDED(rv
);
279 CreateData(segmentSize
, inputData
);
281 uint32_t numWritten
= 0;
282 rv
= writer
->Write(inputData
.BeginReading(), inputData
.Length(), &numWritten
);
283 ASSERT_NS_SUCCEEDED(rv
);
284 EXPECT_EQ(numWritten
, segmentSize
);
286 rv
= writer
->Write(inputData
.BeginReading(), inputData
.Length(), &numWritten
);
287 ASSERT_EQ(NS_BASE_STREAM_WOULD_BLOCK
, rv
);
289 RefPtr
<OutputStreamCallback
> cb
= new OutputStreamCallback();
291 // Register a callback and immediately cancel it.
292 rv
= writer
->AsyncWait(cb
, 0, 0, GetCurrentSerialEventTarget());
293 ASSERT_NS_SUCCEEDED(rv
);
294 rv
= writer
->AsyncWait(nullptr, 0, 0, nullptr);
295 ASSERT_NS_SUCCEEDED(rv
);
297 // Even after consuming the stream and processing pending events, the callback
298 // shouldn't be called as it was cancelled.
299 ConsumeAndValidateStream(reader
, inputData
);
300 NS_ProcessPendingEvents(nullptr);
301 ASSERT_FALSE(cb
->Called());
304 TEST(DataPipe
, Read_AsyncWait_Cancel
)
306 RefPtr
<DataPipeReceiver
> reader
;
307 RefPtr
<DataPipeSender
> writer
;
309 const uint32_t segmentSize
= 1024;
312 NewDataPipe(segmentSize
, getter_AddRefs(writer
), getter_AddRefs(reader
));
313 ASSERT_NS_SUCCEEDED(rv
);
316 CreateData(segmentSize
, inputData
);
318 RefPtr
<InputStreamCallback
> cb
= new InputStreamCallback();
320 // Register a callback and immediately cancel it.
321 rv
= reader
->AsyncWait(cb
, 0, 0, GetCurrentSerialEventTarget());
322 ASSERT_NS_SUCCEEDED(rv
);
324 rv
= reader
->AsyncWait(nullptr, 0, 0, nullptr);
325 ASSERT_NS_SUCCEEDED(rv
);
327 // Write data into the pipe to make the callback become ready.
328 uint32_t numWritten
= 0;
329 rv
= writer
->Write(inputData
.BeginReading(), inputData
.Length(), &numWritten
);
330 ASSERT_NS_SUCCEEDED(rv
);
332 // Even after processing pending events, the callback shouldn't be called as
334 NS_ProcessPendingEvents(nullptr);
335 ASSERT_FALSE(cb
->Called());
337 ConsumeAndValidateStream(reader
, inputData
);
340 TEST(DataPipe
, SerializeReader
)
342 RefPtr
<DataPipeReceiver
> reader
;
343 RefPtr
<DataPipeSender
> writer
;
345 NewDataPipe(1024, getter_AddRefs(writer
), getter_AddRefs(reader
));
346 ASSERT_NS_SUCCEEDED(rv
);
348 IPC::Message
msg(MSG_ROUTING_NONE
, 0);
349 IPC::MessageWriter
msgWriter(msg
);
350 IPC::WriteParam(&msgWriter
, reader
);
352 uint64_t available
= 0;
353 rv
= reader
->Available(&available
);
354 ASSERT_NS_FAILED(rv
);
357 CreateData(512, inputData
);
359 uint32_t numWritten
= 0;
360 rv
= writer
->Write(inputData
.BeginReading(), inputData
.Length(), &numWritten
);
361 ASSERT_NS_SUCCEEDED(rv
);
363 RefPtr
<DataPipeReceiver
> reader2
;
364 IPC::MessageReader
msgReader(msg
);
365 ASSERT_TRUE(IPC::ReadParam(&msgReader
, &reader2
));
366 ASSERT_TRUE(reader2
);
368 rv
= reader2
->Available(&available
);
369 ASSERT_NS_SUCCEEDED(rv
);
370 ASSERT_EQ(available
, 512u);
371 ConsumeAndValidateStream(reader2
, inputData
);
374 } // namespace mozilla::ipc