TestDataPipe.cpp (10866B)
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/. */ 6 7 #include "chrome/common/ipc_message.h" 8 #include "gtest/gtest.h" 9 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" 16 17 namespace mozilla::ipc { 18 19 namespace { 20 21 struct InputStreamCallback : public nsIInputStreamCallback { 22 public: 23 NS_DECL_THREADSAFE_ISUPPORTS 24 25 explicit InputStreamCallback( 26 std::function<nsresult(nsIAsyncInputStream*)> aFunc = nullptr) 27 : mFunc(std::move(aFunc)) {} 28 29 NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream* aStream) override { 30 MOZ_ALWAYS_FALSE(mCalled.exchange(true)); 31 return mFunc ? mFunc(aStream) : NS_OK; 32 } 33 34 bool Called() const { return mCalled; } 35 36 private: 37 virtual ~InputStreamCallback() = default; 38 39 std::atomic<bool> mCalled = false; 40 std::function<nsresult(nsIAsyncInputStream*)> mFunc; 41 }; 42 43 NS_IMPL_ISUPPORTS(InputStreamCallback, nsIInputStreamCallback) 44 45 struct OutputStreamCallback : public nsIOutputStreamCallback { 46 public: 47 NS_DECL_THREADSAFE_ISUPPORTS 48 49 explicit OutputStreamCallback( 50 std::function<nsresult(nsIAsyncOutputStream*)> aFunc = nullptr) 51 : mFunc(std::move(aFunc)) {} 52 53 NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream* aStream) override { 54 MOZ_ALWAYS_FALSE(mCalled.exchange(true)); 55 return mFunc ? mFunc(aStream) : NS_OK; 56 } 57 58 bool Called() const { return mCalled; } 59 60 private: 61 virtual ~OutputStreamCallback() = default; 62 63 std::atomic<bool> mCalled = false; 64 std::function<nsresult(nsIAsyncOutputStream*)> mFunc; 65 }; 66 67 NS_IMPL_ISUPPORTS(OutputStreamCallback, nsIOutputStreamCallback) 68 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; 82 83 aDataOut.SetCapacity(aNumBytes); 84 85 while (aNumBytes > 0) { 86 uint32_t amount = std::min(dataLength, aNumBytes); 87 aDataOut.Append(data, amount); 88 aNumBytes -= amount; 89 } 90 } 91 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)); 101 } 102 103 } // namespace 104 105 TEST(DataPipe, SegmentedReadWrite) 106 { 107 RefPtr<DataPipeReceiver> reader; 108 RefPtr<DataPipeSender> writer; 109 110 nsresult rv = 111 NewDataPipe(1024, getter_AddRefs(writer), getter_AddRefs(reader)); 112 ASSERT_NS_SUCCEEDED(rv); 113 114 nsCString inputData1; 115 CreateData(512, inputData1); 116 117 uint32_t numWritten = 0; 118 rv = writer->Write(inputData1.BeginReading(), inputData1.Length(), 119 &numWritten); 120 ASSERT_NS_SUCCEEDED(rv); 121 EXPECT_EQ(numWritten, 512u); 122 123 uint64_t available = 0; 124 rv = reader->Available(&available); 125 EXPECT_EQ(available, 512u); 126 ConsumeAndValidateStream(reader, inputData1); 127 128 nsCString inputData2; 129 CreateData(1024, inputData2); 130 131 rv = writer->Write(inputData2.BeginReading(), inputData2.Length(), 132 &numWritten); 133 ASSERT_NS_SUCCEEDED(rv); 134 EXPECT_EQ(numWritten, 1024u); 135 136 rv = reader->Available(&available); 137 EXPECT_EQ(available, 1024u); 138 ConsumeAndValidateStream(reader, inputData2); 139 } 140 141 TEST(DataPipe, SegmentedPartialRead) 142 { 143 RefPtr<DataPipeReceiver> reader; 144 RefPtr<DataPipeSender> writer; 145 146 nsresult rv = 147 NewDataPipe(1024, getter_AddRefs(writer), getter_AddRefs(reader)); 148 ASSERT_NS_SUCCEEDED(rv); 149 150 nsCString inputData1; 151 CreateData(512, inputData1); 152 153 uint32_t numWritten = 0; 154 rv = writer->Write(inputData1.BeginReading(), inputData1.Length(), 155 &numWritten); 156 ASSERT_NS_SUCCEEDED(rv); 157 EXPECT_EQ(numWritten, 512u); 158 159 uint64_t available = 0; 160 rv = reader->Available(&available); 161 EXPECT_EQ(available, 512u); 162 ConsumeAndValidateStream(reader, inputData1); 163 164 nsCString inputData2; 165 CreateData(1024, inputData2); 166 167 rv = writer->Write(inputData2.BeginReading(), inputData2.Length(), 168 &numWritten); 169 ASSERT_NS_SUCCEEDED(rv); 170 EXPECT_EQ(numWritten, 1024u); 171 172 rv = reader->Available(&available); 173 EXPECT_EQ(available, 1024u); 174 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)); 180 181 rv = reader->Available(&available); 182 EXPECT_EQ(available, 256u); 183 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)); 189 } 190 191 TEST(DataPipe, Write_AsyncWait) 192 { 193 RefPtr<DataPipeReceiver> reader; 194 RefPtr<DataPipeSender> writer; 195 196 const uint32_t segmentSize = 1024; 197 198 nsresult rv = 199 NewDataPipe(segmentSize, getter_AddRefs(writer), getter_AddRefs(reader)); 200 ASSERT_NS_SUCCEEDED(rv); 201 202 nsCString inputData; 203 CreateData(segmentSize, inputData); 204 205 uint32_t numWritten = 0; 206 rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten); 207 ASSERT_NS_SUCCEEDED(rv); 208 EXPECT_EQ(numWritten, segmentSize); 209 210 rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten); 211 ASSERT_EQ(NS_BASE_STREAM_WOULD_BLOCK, rv); 212 213 RefPtr<OutputStreamCallback> cb = new OutputStreamCallback(); 214 215 rv = writer->AsyncWait(cb, 0, 0, GetCurrentSerialEventTarget()); 216 ASSERT_NS_SUCCEEDED(rv); 217 218 NS_ProcessPendingEvents(nullptr); 219 220 ASSERT_FALSE(cb->Called()); 221 222 ConsumeAndValidateStream(reader, inputData); 223 224 ASSERT_FALSE(cb->Called()); 225 226 NS_ProcessPendingEvents(nullptr); 227 228 ASSERT_TRUE(cb->Called()); 229 } 230 231 TEST(DataPipe, Read_AsyncWait) 232 { 233 RefPtr<DataPipeReceiver> reader; 234 RefPtr<DataPipeSender> writer; 235 236 const uint32_t segmentSize = 1024; 237 238 nsresult rv = 239 NewDataPipe(segmentSize, getter_AddRefs(writer), getter_AddRefs(reader)); 240 ASSERT_NS_SUCCEEDED(rv); 241 242 nsCString inputData; 243 CreateData(segmentSize, inputData); 244 245 RefPtr<InputStreamCallback> cb = new InputStreamCallback(); 246 247 rv = reader->AsyncWait(cb, 0, 0, GetCurrentSerialEventTarget()); 248 ASSERT_NS_SUCCEEDED(rv); 249 250 NS_ProcessPendingEvents(nullptr); 251 252 ASSERT_FALSE(cb->Called()); 253 254 uint32_t numWritten = 0; 255 rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten); 256 ASSERT_NS_SUCCEEDED(rv); 257 258 ASSERT_FALSE(cb->Called()); 259 260 NS_ProcessPendingEvents(nullptr); 261 262 ASSERT_TRUE(cb->Called()); 263 264 ConsumeAndValidateStream(reader, inputData); 265 } 266 267 TEST(DataPipe, Write_AsyncWait_Cancel) 268 { 269 RefPtr<DataPipeReceiver> reader; 270 RefPtr<DataPipeSender> writer; 271 272 const uint32_t segmentSize = 1024; 273 274 nsresult rv = 275 NewDataPipe(segmentSize, getter_AddRefs(writer), getter_AddRefs(reader)); 276 ASSERT_NS_SUCCEEDED(rv); 277 278 nsCString inputData; 279 CreateData(segmentSize, inputData); 280 281 uint32_t numWritten = 0; 282 rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten); 283 ASSERT_NS_SUCCEEDED(rv); 284 EXPECT_EQ(numWritten, segmentSize); 285 286 rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten); 287 ASSERT_EQ(NS_BASE_STREAM_WOULD_BLOCK, rv); 288 289 RefPtr<OutputStreamCallback> cb = new OutputStreamCallback(); 290 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); 296 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()); 302 } 303 304 TEST(DataPipe, Read_AsyncWait_Cancel) 305 { 306 RefPtr<DataPipeReceiver> reader; 307 RefPtr<DataPipeSender> writer; 308 309 const uint32_t segmentSize = 1024; 310 311 nsresult rv = 312 NewDataPipe(segmentSize, getter_AddRefs(writer), getter_AddRefs(reader)); 313 ASSERT_NS_SUCCEEDED(rv); 314 315 nsCString inputData; 316 CreateData(segmentSize, inputData); 317 318 RefPtr<InputStreamCallback> cb = new InputStreamCallback(); 319 320 // Register a callback and immediately cancel it. 321 rv = reader->AsyncWait(cb, 0, 0, GetCurrentSerialEventTarget()); 322 ASSERT_NS_SUCCEEDED(rv); 323 324 rv = reader->AsyncWait(nullptr, 0, 0, nullptr); 325 ASSERT_NS_SUCCEEDED(rv); 326 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); 331 332 // Even after processing pending events, the callback shouldn't be called as 333 // it was cancelled. 334 NS_ProcessPendingEvents(nullptr); 335 ASSERT_FALSE(cb->Called()); 336 337 ConsumeAndValidateStream(reader, inputData); 338 } 339 340 TEST(DataPipe, SerializeReader) 341 { 342 RefPtr<DataPipeReceiver> reader; 343 RefPtr<DataPipeSender> writer; 344 nsresult rv = 345 NewDataPipe(1024, getter_AddRefs(writer), getter_AddRefs(reader)); 346 ASSERT_NS_SUCCEEDED(rv); 347 348 IPC::Message msg(MSG_ROUTING_NONE, 0); 349 IPC::MessageWriter msgWriter(msg); 350 IPC::WriteParam(&msgWriter, reader); 351 352 uint64_t available = 0; 353 rv = reader->Available(&available); 354 ASSERT_NS_FAILED(rv); 355 356 nsCString inputData; 357 CreateData(512, inputData); 358 359 uint32_t numWritten = 0; 360 rv = writer->Write(inputData.BeginReading(), inputData.Length(), &numWritten); 361 ASSERT_NS_SUCCEEDED(rv); 362 363 RefPtr<DataPipeReceiver> reader2; 364 IPC::MessageReader msgReader(msg); 365 ASSERT_TRUE(IPC::ReadParam(&msgReader, &reader2)); 366 ASSERT_TRUE(reader2); 367 368 rv = reader2->Available(&available); 369 ASSERT_NS_SUCCEEDED(rv); 370 ASSERT_EQ(available, 512u); 371 ConsumeAndValidateStream(reader2, inputData); 372 } 373 374 } // namespace mozilla::ipc