| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 "mojo/edk/system/raw_channel.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 #include <stdint.h> | |
| 9 #include <stdio.h> | |
| 10 #include <utility> | |
| 11 #include <vector> | |
| 12 | |
| 13 #include "base/bind.h" | |
| 14 #include "base/files/file_path.h" | |
| 15 #include "base/files/file_util.h" | |
| 16 #include "base/files/scoped_file.h" | |
| 17 #include "base/files/scoped_temp_dir.h" | |
| 18 #include "base/location.h" | |
| 19 #include "base/logging.h" | |
| 20 #include "base/memory/scoped_ptr.h" | |
| 21 #include "base/memory/scoped_vector.h" | |
| 22 #include "base/rand_util.h" | |
| 23 #include "base/synchronization/lock.h" | |
| 24 #include "base/synchronization/waitable_event.h" | |
| 25 #include "base/test/test_io_thread.h" | |
| 26 #include "base/threading/simple_thread.h" | |
| 27 #include "build/build_config.h" | |
| 28 #include "mojo/edk/embedder/embedder.h" | |
| 29 #include "mojo/edk/embedder/embedder_internal.h" | |
| 30 #include "mojo/edk/embedder/platform_channel_pair.h" | |
| 31 #include "mojo/edk/embedder/platform_handle.h" | |
| 32 #include "mojo/edk/embedder/scoped_platform_handle.h" | |
| 33 #include "mojo/edk/system/message_in_transit.h" | |
| 34 #include "mojo/edk/system/test_utils.h" | |
| 35 #include "mojo/edk/system/transport_data.h" | |
| 36 #include "mojo/edk/test/test_utils.h" | |
| 37 #include "mojo/public/cpp/system/macros.h" | |
| 38 #include "testing/gtest/include/gtest/gtest.h" | |
| 39 | |
| 40 namespace mojo { | |
| 41 namespace edk { | |
| 42 namespace { | |
| 43 | |
| 44 scoped_ptr<MessageInTransit> MakeTestMessage(uint32_t num_bytes) { | |
| 45 std::vector<unsigned char> bytes(num_bytes, 0); | |
| 46 for (size_t i = 0; i < num_bytes; i++) | |
| 47 bytes[i] = static_cast<unsigned char>(i + num_bytes); | |
| 48 return make_scoped_ptr( | |
| 49 new MessageInTransit(MessageInTransit::Type::MESSAGE, | |
| 50 num_bytes, bytes.empty() ? nullptr : &bytes[0])); | |
| 51 } | |
| 52 | |
| 53 bool CheckMessageData(const void* bytes, uint32_t num_bytes) { | |
| 54 const unsigned char* b = static_cast<const unsigned char*>(bytes); | |
| 55 for (uint32_t i = 0; i < num_bytes; i++) { | |
| 56 if (b[i] != static_cast<unsigned char>(i + num_bytes)) | |
| 57 return false; | |
| 58 } | |
| 59 return true; | |
| 60 } | |
| 61 | |
| 62 void InitOnIOThread(RawChannel* raw_channel, RawChannel::Delegate* delegate) { | |
| 63 raw_channel->Init(delegate); | |
| 64 raw_channel->EnsureLazyInitialized(); | |
| 65 } | |
| 66 | |
| 67 bool WriteTestMessageToHandle(const PlatformHandle& handle, | |
| 68 uint32_t num_bytes) { | |
| 69 scoped_ptr<MessageInTransit> message(MakeTestMessage(num_bytes)); | |
| 70 | |
| 71 size_t write_size = 0; | |
| 72 test::BlockingWrite(handle, message->main_buffer(), | |
| 73 message->main_buffer_size(), &write_size); | |
| 74 return write_size == message->main_buffer_size(); | |
| 75 } | |
| 76 | |
| 77 // ----------------------------------------------------------------------------- | |
| 78 | |
| 79 class RawChannelTest : public testing::Test { | |
| 80 public: | |
| 81 RawChannelTest() {} | |
| 82 ~RawChannelTest() override {} | |
| 83 | |
| 84 void SetUp() override { | |
| 85 PlatformChannelPair channel_pair; | |
| 86 handles[0] = channel_pair.PassServerHandle(); | |
| 87 handles[1] = channel_pair.PassClientHandle();\ | |
| 88 } | |
| 89 | |
| 90 void TearDown() override { | |
| 91 handles[0].reset(); | |
| 92 handles[1].reset(); | |
| 93 } | |
| 94 | |
| 95 void FlushIOThread() { | |
| 96 base::WaitableEvent event(false, false); | |
| 97 internal::g_io_thread_task_runner->PostTask( | |
| 98 FROM_HERE, | |
| 99 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event))); | |
| 100 event.Wait(); | |
| 101 } | |
| 102 | |
| 103 protected: | |
| 104 ScopedPlatformHandle handles[2]; | |
| 105 | |
| 106 private: | |
| 107 MOJO_DISALLOW_COPY_AND_ASSIGN(RawChannelTest); | |
| 108 }; | |
| 109 | |
| 110 // RawChannelTest.WriteMessage ------------------------------------------------- | |
| 111 | |
| 112 class WriteOnlyRawChannelDelegate : public RawChannel::Delegate { | |
| 113 public: | |
| 114 WriteOnlyRawChannelDelegate() {} | |
| 115 ~WriteOnlyRawChannelDelegate() override {} | |
| 116 | |
| 117 // |RawChannel::Delegate| implementation: | |
| 118 void OnReadMessage( | |
| 119 const MessageInTransit::View& /*message_view*/, | |
| 120 ScopedPlatformHandleVectorPtr /*platform_handles*/) override { | |
| 121 CHECK(false); // Should not get called. | |
| 122 } | |
| 123 void OnError(Error error) override { | |
| 124 // We'll get a read (shutdown) error when the connection is closed. | |
| 125 CHECK_EQ(error, ERROR_READ_SHUTDOWN); | |
| 126 } | |
| 127 | |
| 128 private: | |
| 129 MOJO_DISALLOW_COPY_AND_ASSIGN(WriteOnlyRawChannelDelegate); | |
| 130 }; | |
| 131 | |
| 132 static const unsigned kMessageReaderSleepMs = 1; | |
| 133 static const size_t kMessageReaderMaxPollIterations = 3000; | |
| 134 | |
| 135 class TestMessageReaderAndChecker { | |
| 136 public: | |
| 137 explicit TestMessageReaderAndChecker(PlatformHandle handle) | |
| 138 : handle_(handle) {} | |
| 139 ~TestMessageReaderAndChecker() { CHECK(bytes_.empty()); } | |
| 140 | |
| 141 bool ReadAndCheckNextMessage(uint32_t expected_size) { | |
| 142 unsigned char buffer[4096]; | |
| 143 | |
| 144 for (size_t i = 0; i < kMessageReaderMaxPollIterations;) { | |
| 145 size_t read_size = 0; | |
| 146 CHECK(test::NonBlockingRead(handle_, buffer, sizeof(buffer), &read_size)); | |
| 147 | |
| 148 // Append newly-read data to |bytes_|. | |
| 149 bytes_.insert(bytes_.end(), buffer, buffer + read_size); | |
| 150 | |
| 151 // If we have the header.... | |
| 152 size_t message_size; | |
| 153 if (MessageInTransit::GetNextMessageSize( | |
| 154 bytes_.empty() ? nullptr : &bytes_[0], bytes_.size(), | |
| 155 &message_size)) { | |
| 156 // If we've read the whole message.... | |
| 157 if (bytes_.size() >= message_size) { | |
| 158 bool rv = true; | |
| 159 MessageInTransit::View message_view(message_size, &bytes_[0]); | |
| 160 CHECK_EQ(message_view.main_buffer_size(), message_size); | |
| 161 | |
| 162 if (message_view.num_bytes() != expected_size) { | |
| 163 LOG(ERROR) << "Wrong size: " << message_size << " instead of " | |
| 164 << expected_size << " bytes."; | |
| 165 rv = false; | |
| 166 } else if (!CheckMessageData(message_view.bytes(), | |
| 167 message_view.num_bytes())) { | |
| 168 LOG(ERROR) << "Incorrect message bytes."; | |
| 169 rv = false; | |
| 170 } | |
| 171 | |
| 172 // Erase message data. | |
| 173 bytes_.erase(bytes_.begin(), | |
| 174 bytes_.begin() + message_view.main_buffer_size()); | |
| 175 return rv; | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 if (static_cast<size_t>(read_size) < sizeof(buffer)) { | |
| 180 i++; | |
| 181 test::Sleep(test::DeadlineFromMilliseconds(kMessageReaderSleepMs)); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 LOG(ERROR) << "Too many iterations."; | |
| 186 return false; | |
| 187 } | |
| 188 | |
| 189 private: | |
| 190 const PlatformHandle handle_; | |
| 191 | |
| 192 // The start of the received data should always be on a message boundary. | |
| 193 std::vector<unsigned char> bytes_; | |
| 194 | |
| 195 MOJO_DISALLOW_COPY_AND_ASSIGN(TestMessageReaderAndChecker); | |
| 196 }; | |
| 197 | |
| 198 // Tests writing (and verifies reading using our own custom reader). | |
| 199 TEST_F(RawChannelTest, WriteMessage) { | |
| 200 WriteOnlyRawChannelDelegate delegate; | |
| 201 RawChannel* rc = RawChannel::Create(std::move(handles[0])); | |
| 202 TestMessageReaderAndChecker checker(handles[1].get()); | |
| 203 internal::g_io_thread_task_runner->PostTask( | |
| 204 FROM_HERE, | |
| 205 base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate))); | |
| 206 | |
| 207 // Write and read, for a variety of sizes. | |
| 208 for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) { | |
| 209 EXPECT_TRUE(rc->WriteMessage(MakeTestMessage(size))); | |
| 210 EXPECT_TRUE(checker.ReadAndCheckNextMessage(size)) << size; | |
| 211 } | |
| 212 | |
| 213 // Write/queue and read afterwards, for a variety of sizes. | |
| 214 for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) | |
| 215 EXPECT_TRUE(rc->WriteMessage(MakeTestMessage(size))); | |
| 216 for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) | |
| 217 EXPECT_TRUE(checker.ReadAndCheckNextMessage(size)) << size; | |
| 218 | |
| 219 internal::g_io_thread_task_runner->PostTask( | |
| 220 FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc))); | |
| 221 } | |
| 222 | |
| 223 // RawChannelTest.OnReadMessage ------------------------------------------------ | |
| 224 | |
| 225 class ReadCheckerRawChannelDelegate : public RawChannel::Delegate { | |
| 226 public: | |
| 227 ReadCheckerRawChannelDelegate() : done_event_(false, false), position_(0) {} | |
| 228 ~ReadCheckerRawChannelDelegate() override {} | |
| 229 | |
| 230 // |RawChannel::Delegate| implementation (called on the I/O thread): | |
| 231 void OnReadMessage( | |
| 232 const MessageInTransit::View& message_view, | |
| 233 ScopedPlatformHandleVectorPtr platform_handles) override { | |
| 234 EXPECT_FALSE(platform_handles); | |
| 235 | |
| 236 size_t position; | |
| 237 size_t expected_size; | |
| 238 bool should_signal = false; | |
| 239 { | |
| 240 base::AutoLock locker(lock_); | |
| 241 CHECK_LT(position_, expected_sizes_.size()); | |
| 242 position = position_; | |
| 243 expected_size = expected_sizes_[position]; | |
| 244 position_++; | |
| 245 if (position_ >= expected_sizes_.size()) | |
| 246 should_signal = true; | |
| 247 } | |
| 248 | |
| 249 EXPECT_EQ(expected_size, message_view.num_bytes()) << position; | |
| 250 if (message_view.num_bytes() == expected_size) { | |
| 251 EXPECT_TRUE( | |
| 252 CheckMessageData(message_view.bytes(), message_view.num_bytes())) | |
| 253 << position; | |
| 254 } | |
| 255 | |
| 256 if (should_signal) | |
| 257 done_event_.Signal(); | |
| 258 } | |
| 259 void OnError(Error error) override { | |
| 260 // We'll get a read (shutdown) error when the connection is closed. | |
| 261 CHECK_EQ(error, ERROR_READ_SHUTDOWN); | |
| 262 } | |
| 263 | |
| 264 // Waits for all the messages (of sizes |expected_sizes_|) to be seen. | |
| 265 void Wait() { done_event_.Wait(); } | |
| 266 | |
| 267 void SetExpectedSizes(const std::vector<uint32_t>& expected_sizes) { | |
| 268 base::AutoLock locker(lock_); | |
| 269 CHECK_EQ(position_, expected_sizes_.size()); | |
| 270 expected_sizes_ = expected_sizes; | |
| 271 position_ = 0; | |
| 272 } | |
| 273 | |
| 274 private: | |
| 275 base::WaitableEvent done_event_; | |
| 276 | |
| 277 base::Lock lock_; // Protects the following members. | |
| 278 std::vector<uint32_t> expected_sizes_; | |
| 279 size_t position_; | |
| 280 | |
| 281 MOJO_DISALLOW_COPY_AND_ASSIGN(ReadCheckerRawChannelDelegate); | |
| 282 }; | |
| 283 | |
| 284 // Tests reading (writing using our own custom writer). | |
| 285 TEST_F(RawChannelTest, OnReadMessage) { | |
| 286 ReadCheckerRawChannelDelegate delegate; | |
| 287 RawChannel* rc = RawChannel::Create(std::move(handles[0])); | |
| 288 internal::g_io_thread_task_runner->PostTask( | |
| 289 FROM_HERE, | |
| 290 base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate))); | |
| 291 | |
| 292 // Write and read, for a variety of sizes. | |
| 293 for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) { | |
| 294 delegate.SetExpectedSizes(std::vector<uint32_t>(1, size)); | |
| 295 | |
| 296 EXPECT_TRUE(WriteTestMessageToHandle(handles[1].get(), size)); | |
| 297 | |
| 298 delegate.Wait(); | |
| 299 } | |
| 300 | |
| 301 // Set up reader and write as fast as we can. | |
| 302 // Write/queue and read afterwards, for a variety of sizes. | |
| 303 std::vector<uint32_t> expected_sizes; | |
| 304 for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) | |
| 305 expected_sizes.push_back(size); | |
| 306 delegate.SetExpectedSizes(expected_sizes); | |
| 307 for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) | |
| 308 EXPECT_TRUE(WriteTestMessageToHandle(handles[1].get(), size)); | |
| 309 delegate.Wait(); | |
| 310 | |
| 311 internal::g_io_thread_task_runner->PostTask( | |
| 312 FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc))); | |
| 313 } | |
| 314 | |
| 315 // RawChannelTest.WriteMessageAndOnReadMessage --------------------------------- | |
| 316 | |
| 317 class RawChannelWriterThread : public base::SimpleThread { | |
| 318 public: | |
| 319 RawChannelWriterThread(RawChannel* raw_channel, size_t write_count) | |
| 320 : base::SimpleThread("raw_channel_writer_thread"), | |
| 321 raw_channel_(raw_channel), | |
| 322 left_to_write_(write_count) {} | |
| 323 | |
| 324 ~RawChannelWriterThread() override { Join(); } | |
| 325 | |
| 326 private: | |
| 327 void Run() override { | |
| 328 static const int kMaxRandomMessageSize = 25000; | |
| 329 | |
| 330 while (left_to_write_-- > 0) { | |
| 331 EXPECT_TRUE(raw_channel_->WriteMessage(MakeTestMessage( | |
| 332 static_cast<uint32_t>(base::RandInt(1, kMaxRandomMessageSize))))); | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 RawChannel* const raw_channel_; | |
| 337 size_t left_to_write_; | |
| 338 | |
| 339 MOJO_DISALLOW_COPY_AND_ASSIGN(RawChannelWriterThread); | |
| 340 }; | |
| 341 | |
| 342 class ReadCountdownRawChannelDelegate : public RawChannel::Delegate { | |
| 343 public: | |
| 344 explicit ReadCountdownRawChannelDelegate(size_t expected_count) | |
| 345 : done_event_(false, false), expected_count_(expected_count), count_(0) {} | |
| 346 ~ReadCountdownRawChannelDelegate() override {} | |
| 347 | |
| 348 // |RawChannel::Delegate| implementation (called on the I/O thread): | |
| 349 void OnReadMessage( | |
| 350 const MessageInTransit::View& message_view, | |
| 351 ScopedPlatformHandleVectorPtr platform_handles) override { | |
| 352 EXPECT_FALSE(platform_handles); | |
| 353 | |
| 354 EXPECT_LT(count_, expected_count_); | |
| 355 count_++; | |
| 356 | |
| 357 EXPECT_TRUE( | |
| 358 CheckMessageData(message_view.bytes(), message_view.num_bytes())); | |
| 359 | |
| 360 if (count_ >= expected_count_) | |
| 361 done_event_.Signal(); | |
| 362 } | |
| 363 void OnError(Error error) override { | |
| 364 // We'll get a read (shutdown) error when the connection is closed. | |
| 365 CHECK_EQ(error, ERROR_READ_SHUTDOWN); | |
| 366 } | |
| 367 | |
| 368 // Waits for all the messages to have been seen. | |
| 369 void Wait() { done_event_.Wait(); } | |
| 370 | |
| 371 private: | |
| 372 base::WaitableEvent done_event_; | |
| 373 size_t expected_count_; | |
| 374 size_t count_; | |
| 375 | |
| 376 MOJO_DISALLOW_COPY_AND_ASSIGN(ReadCountdownRawChannelDelegate); | |
| 377 }; | |
| 378 | |
| 379 TEST_F(RawChannelTest, WriteMessageAndOnReadMessage) { | |
| 380 static const size_t kNumWriterThreads = 10; | |
| 381 static const size_t kNumWriteMessagesPerThread = 400; | |
| 382 | |
| 383 WriteOnlyRawChannelDelegate writer_delegate; | |
| 384 RawChannel* writer_rc = RawChannel::Create(std::move(handles[0])); | |
| 385 internal::g_io_thread_task_runner->PostTask( | |
| 386 FROM_HERE, | |
| 387 base::Bind(&InitOnIOThread, writer_rc, | |
| 388 base::Unretained(&writer_delegate))); | |
| 389 | |
| 390 ReadCountdownRawChannelDelegate reader_delegate(kNumWriterThreads * | |
| 391 kNumWriteMessagesPerThread); | |
| 392 RawChannel* reader_rc = RawChannel::Create(std::move(handles[1])); | |
| 393 internal::g_io_thread_task_runner->PostTask( | |
| 394 FROM_HERE, | |
| 395 base::Bind(&InitOnIOThread, reader_rc, | |
| 396 base::Unretained(&reader_delegate))); | |
| 397 | |
| 398 { | |
| 399 ScopedVector<RawChannelWriterThread> writer_threads; | |
| 400 for (size_t i = 0; i < kNumWriterThreads; i++) { | |
| 401 writer_threads.push_back(new RawChannelWriterThread( | |
| 402 writer_rc, kNumWriteMessagesPerThread)); | |
| 403 } | |
| 404 for (size_t i = 0; i < writer_threads.size(); i++) | |
| 405 writer_threads[i]->Start(); | |
| 406 } // Joins all the writer threads. | |
| 407 | |
| 408 // Sleep a bit, to let any extraneous reads be processed. (There shouldn't be | |
| 409 // any, but we want to know about them.) | |
| 410 test::Sleep(test::DeadlineFromMilliseconds(100)); | |
| 411 | |
| 412 // Wait for reading to finish. | |
| 413 reader_delegate.Wait(); | |
| 414 | |
| 415 internal::g_io_thread_task_runner->PostTask( | |
| 416 FROM_HERE, | |
| 417 base::Bind(&RawChannel::Shutdown, base::Unretained(reader_rc))); | |
| 418 | |
| 419 internal::g_io_thread_task_runner->PostTask( | |
| 420 FROM_HERE, | |
| 421 base::Bind(&RawChannel::Shutdown, base::Unretained(writer_rc))); | |
| 422 } | |
| 423 | |
| 424 // RawChannelTest.OnError ------------------------------------------------------ | |
| 425 | |
| 426 class ErrorRecordingRawChannelDelegate | |
| 427 : public ReadCountdownRawChannelDelegate { | |
| 428 public: | |
| 429 ErrorRecordingRawChannelDelegate(size_t expected_read_count, | |
| 430 bool expect_read_error, | |
| 431 bool expect_write_error) | |
| 432 : ReadCountdownRawChannelDelegate(expected_read_count), | |
| 433 got_read_error_event_(false, false), | |
| 434 got_write_error_event_(false, false), | |
| 435 expecting_read_error_(expect_read_error), | |
| 436 expecting_write_error_(expect_write_error) {} | |
| 437 | |
| 438 ~ErrorRecordingRawChannelDelegate() override {} | |
| 439 | |
| 440 void OnError(Error error) override { | |
| 441 switch (error) { | |
| 442 case ERROR_READ_SHUTDOWN: | |
| 443 ASSERT_TRUE(expecting_read_error_); | |
| 444 expecting_read_error_ = false; | |
| 445 got_read_error_event_.Signal(); | |
| 446 break; | |
| 447 case ERROR_READ_BROKEN: | |
| 448 // TODO(vtl): Test broken connections. | |
| 449 CHECK(false); | |
| 450 break; | |
| 451 case ERROR_READ_BAD_MESSAGE: | |
| 452 // TODO(vtl): Test reception/detection of bad messages. | |
| 453 CHECK(false); | |
| 454 break; | |
| 455 case ERROR_READ_UNKNOWN: | |
| 456 // TODO(vtl): Test however it is we might get here. | |
| 457 CHECK(false); | |
| 458 break; | |
| 459 case ERROR_WRITE: | |
| 460 ASSERT_TRUE(expecting_write_error_); | |
| 461 expecting_write_error_ = false; | |
| 462 got_write_error_event_.Signal(); | |
| 463 break; | |
| 464 } | |
| 465 } | |
| 466 | |
| 467 void WaitForReadError() { got_read_error_event_.Wait(); } | |
| 468 void WaitForWriteError() { got_write_error_event_.Wait(); } | |
| 469 | |
| 470 private: | |
| 471 base::WaitableEvent got_read_error_event_; | |
| 472 base::WaitableEvent got_write_error_event_; | |
| 473 | |
| 474 bool expecting_read_error_; | |
| 475 bool expecting_write_error_; | |
| 476 | |
| 477 MOJO_DISALLOW_COPY_AND_ASSIGN(ErrorRecordingRawChannelDelegate); | |
| 478 }; | |
| 479 | |
| 480 // Tests (fatal) errors. | |
| 481 TEST_F(RawChannelTest, OnError) { | |
| 482 ErrorRecordingRawChannelDelegate delegate(0, true, true); | |
| 483 RawChannel* rc = RawChannel::Create(std::move(handles[0])); | |
| 484 internal::g_io_thread_task_runner->PostTask( | |
| 485 FROM_HERE, | |
| 486 base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate))); | |
| 487 FlushIOThread(); | |
| 488 | |
| 489 // Close the handle of the other end, which should make writing fail. | |
| 490 handles[1].reset(); | |
| 491 | |
| 492 EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(1))); | |
| 493 | |
| 494 // We should get a write error. | |
| 495 delegate.WaitForWriteError(); | |
| 496 | |
| 497 // We should also get a read error. | |
| 498 delegate.WaitForReadError(); | |
| 499 | |
| 500 EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(2))); | |
| 501 | |
| 502 // Sleep a bit, to make sure we don't get another |OnError()| | |
| 503 // notification. (If we actually get another one, |OnError()| crashes.) | |
| 504 test::Sleep(test::DeadlineFromMilliseconds(20)); | |
| 505 | |
| 506 internal::g_io_thread_task_runner->PostTask( | |
| 507 FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc))); | |
| 508 } | |
| 509 | |
| 510 // RawChannelTest.ReadUnaffectedByWriteError ----------------------------------- | |
| 511 | |
| 512 TEST_F(RawChannelTest, ReadUnaffectedByWriteError) { | |
| 513 const size_t kMessageCount = 5; | |
| 514 | |
| 515 // Write a few messages into the other end. | |
| 516 uint32_t message_size = 1; | |
| 517 for (size_t i = 0; i < kMessageCount; | |
| 518 i++, message_size += message_size / 2 + 1) | |
| 519 EXPECT_TRUE(WriteTestMessageToHandle(handles[1].get(), message_size)); | |
| 520 | |
| 521 // Close the other end, which should make writing fail. | |
| 522 handles[1].reset(); | |
| 523 | |
| 524 // Only start up reading here. The system buffer should still contain the | |
| 525 // messages that were written. | |
| 526 ErrorRecordingRawChannelDelegate delegate(kMessageCount, true, true); | |
| 527 RawChannel* rc = RawChannel::Create(std::move(handles[0])); | |
| 528 internal::g_io_thread_task_runner->PostTask( | |
| 529 FROM_HERE, | |
| 530 base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate))); | |
| 531 FlushIOThread(); | |
| 532 | |
| 533 EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(1))); | |
| 534 | |
| 535 // We should definitely get a write error. | |
| 536 delegate.WaitForWriteError(); | |
| 537 | |
| 538 // Wait for reading to finish. A writing failure shouldn't affect reading. | |
| 539 delegate.Wait(); | |
| 540 | |
| 541 // And then we should get a read error. | |
| 542 delegate.WaitForReadError(); | |
| 543 | |
| 544 internal::g_io_thread_task_runner->PostTask( | |
| 545 FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc))); | |
| 546 } | |
| 547 | |
| 548 // RawChannelTest.ReadWritePlatformHandles ------------------------------------- | |
| 549 | |
| 550 class ReadPlatformHandlesCheckerRawChannelDelegate | |
| 551 : public RawChannel::Delegate { | |
| 552 public: | |
| 553 ReadPlatformHandlesCheckerRawChannelDelegate() : done_event_(false, false) {} | |
| 554 ~ReadPlatformHandlesCheckerRawChannelDelegate() override {} | |
| 555 | |
| 556 // |RawChannel::Delegate| implementation (called on the I/O thread): | |
| 557 void OnReadMessage( | |
| 558 const MessageInTransit::View& message_view, | |
| 559 ScopedPlatformHandleVectorPtr platform_handles) override { | |
| 560 const char kHello[] = "hello"; | |
| 561 | |
| 562 EXPECT_EQ(sizeof(kHello), message_view.num_bytes()); | |
| 563 EXPECT_STREQ(kHello, static_cast<const char*>(message_view.bytes())); | |
| 564 | |
| 565 ASSERT_TRUE(platform_handles); | |
| 566 ASSERT_EQ(2u, platform_handles->size()); | |
| 567 ScopedPlatformHandle h1(platform_handles->at(0)); | |
| 568 EXPECT_TRUE(h1.is_valid()); | |
| 569 ScopedPlatformHandle h2(platform_handles->at(1)); | |
| 570 EXPECT_TRUE(h2.is_valid()); | |
| 571 platform_handles->clear(); | |
| 572 | |
| 573 { | |
| 574 char buffer[100] = {}; | |
| 575 | |
| 576 base::ScopedFILE fp(test::FILEFromPlatformHandle(std::move(h1), "rb")); | |
| 577 EXPECT_TRUE(fp); | |
| 578 rewind(fp.get()); | |
| 579 EXPECT_EQ(1u, fread(buffer, 1, sizeof(buffer), fp.get())); | |
| 580 EXPECT_EQ('1', buffer[0]); | |
| 581 } | |
| 582 | |
| 583 { | |
| 584 char buffer[100] = {}; | |
| 585 base::ScopedFILE fp(test::FILEFromPlatformHandle(std::move(h2), "rb")); | |
| 586 EXPECT_TRUE(fp); | |
| 587 rewind(fp.get()); | |
| 588 EXPECT_EQ(1u, fread(buffer, 1, sizeof(buffer), fp.get())); | |
| 589 EXPECT_EQ('2', buffer[0]); | |
| 590 } | |
| 591 | |
| 592 done_event_.Signal(); | |
| 593 } | |
| 594 void OnError(Error error) override { | |
| 595 // We'll get a read (shutdown) error when the connection is closed. | |
| 596 CHECK_EQ(error, ERROR_READ_SHUTDOWN); | |
| 597 } | |
| 598 | |
| 599 void Wait() { done_event_.Wait(); } | |
| 600 | |
| 601 private: | |
| 602 base::WaitableEvent done_event_; | |
| 603 | |
| 604 MOJO_DISALLOW_COPY_AND_ASSIGN(ReadPlatformHandlesCheckerRawChannelDelegate); | |
| 605 }; | |
| 606 | |
| 607 TEST_F(RawChannelTest, ReadWritePlatformHandles) { | |
| 608 base::ScopedTempDir temp_dir; | |
| 609 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 610 | |
| 611 WriteOnlyRawChannelDelegate write_delegate; | |
| 612 RawChannel* rc_write = RawChannel::Create(std::move(handles[0])); | |
| 613 internal::g_io_thread_task_runner->PostTask( | |
| 614 FROM_HERE, | |
| 615 base::Bind(&InitOnIOThread, rc_write, base::Unretained(&write_delegate))); | |
| 616 | |
| 617 ReadPlatformHandlesCheckerRawChannelDelegate read_delegate; | |
| 618 RawChannel* rc_read = RawChannel::Create(std::move(handles[1])); | |
| 619 internal::g_io_thread_task_runner->PostTask( | |
| 620 FROM_HERE, | |
| 621 base::Bind(&InitOnIOThread, rc_read, base::Unretained(&read_delegate))); | |
| 622 | |
| 623 base::FilePath unused; | |
| 624 base::ScopedFILE fp1( | |
| 625 base::CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused)); | |
| 626 EXPECT_EQ(1u, fwrite("1", 1, 1, fp1.get())); | |
| 627 base::ScopedFILE fp2( | |
| 628 base::CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused)); | |
| 629 EXPECT_EQ(1u, fwrite("2", 1, 1, fp2.get())); | |
| 630 | |
| 631 { | |
| 632 const char kHello[] = "hello"; | |
| 633 ScopedPlatformHandleVectorPtr platform_handles(new PlatformHandleVector()); | |
| 634 platform_handles->push_back( | |
| 635 test::PlatformHandleFromFILE(std::move(fp1)).release()); | |
| 636 platform_handles->push_back( | |
| 637 test::PlatformHandleFromFILE(std::move(fp2)).release()); | |
| 638 | |
| 639 scoped_ptr<MessageInTransit> message( | |
| 640 new MessageInTransit(MessageInTransit::Type::MESSAGE, | |
| 641 sizeof(kHello), kHello)); | |
| 642 message->SetTransportData(make_scoped_ptr( | |
| 643 new TransportData(std::move(platform_handles), | |
| 644 rc_write->GetSerializedPlatformHandleSize()))); | |
| 645 EXPECT_TRUE(rc_write->WriteMessage(std::move(message))); | |
| 646 } | |
| 647 | |
| 648 read_delegate.Wait(); | |
| 649 | |
| 650 internal::g_io_thread_task_runner->PostTask( | |
| 651 FROM_HERE, | |
| 652 base::Bind(&RawChannel::Shutdown, base::Unretained(rc_read))); | |
| 653 internal::g_io_thread_task_runner->PostTask( | |
| 654 FROM_HERE, | |
| 655 base::Bind(&RawChannel::Shutdown, base::Unretained(rc_write))); | |
| 656 } | |
| 657 | |
| 658 } // namespace | |
| 659 } // namespace edk | |
| 660 } // namespace mojo | |
| OLD | NEW |