| // Copyright 2016 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifdef UNSAFE_BUFFERS_BUILD | 
 | // TODO(crbug.com/40284755): Remove this and spanify to fix the errors. | 
 | #pragma allow_unsafe_buffers | 
 | #endif | 
 |  | 
 | #include "base/files/file_descriptor_watcher_posix.h" | 
 |  | 
 | #include <unistd.h> | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/containers/span.h" | 
 | #include "base/files/file_util.h" | 
 | #include "base/functional/bind.h" | 
 | #include "base/memory/ptr_util.h" | 
 | #include "base/message_loop/message_pump_type.h" | 
 | #include "base/posix/eintr_wrapper.h" | 
 | #include "base/run_loop.h" | 
 | #include "base/test/task_environment.h" | 
 | #include "base/test/test_timeouts.h" | 
 | #include "base/threading/platform_thread.h" | 
 | #include "base/threading/thread.h" | 
 | #include "base/threading/thread_checker_impl.h" | 
 | #include "build/build_config.h" | 
 | #include "testing/gmock/include/gmock/gmock.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace base { | 
 |  | 
 | namespace { | 
 |  | 
 | class Mock { | 
 |  public: | 
 |   Mock() = default; | 
 |   Mock(const Mock&) = delete; | 
 |   Mock& operator=(const Mock&) = delete; | 
 |  | 
 |   MOCK_METHOD0(ReadableCallback, void()); | 
 |   MOCK_METHOD0(WritableCallback, void()); | 
 |   MOCK_METHOD0(ReadableCallback2, void()); | 
 |   MOCK_METHOD0(WritableCallback2, void()); | 
 | }; | 
 |  | 
 | enum class FileDescriptorWatcherTestType { | 
 |   MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD, | 
 |   MESSAGE_PUMP_FOR_IO_ON_OTHER_THREAD, | 
 | }; | 
 |  | 
 | class FileDescriptorWatcherTest | 
 |     : public testing::TestWithParam<FileDescriptorWatcherTestType> { | 
 |  public: | 
 |   FileDescriptorWatcherTest() | 
 |       : task_environment_(std::make_unique<test::TaskEnvironment>( | 
 |             GetParam() == FileDescriptorWatcherTestType:: | 
 |                               MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD | 
 |                 ? test::TaskEnvironment::MainThreadType::IO | 
 |                 : test::TaskEnvironment::MainThreadType::DEFAULT)), | 
 |         other_thread_("FileDescriptorWatcherTest_OtherThread") {} | 
 |   FileDescriptorWatcherTest(const FileDescriptorWatcherTest&) = delete; | 
 |   FileDescriptorWatcherTest& operator=(const FileDescriptorWatcherTest&) = | 
 |       delete; | 
 |   ~FileDescriptorWatcherTest() override = default; | 
 |  | 
 |   void SetUp() override { | 
 |     ASSERT_EQ(0, pipe(pipe_fds_)); | 
 |     ASSERT_EQ(0, pipe(pipe_fds2_)); | 
 |  | 
 |     scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner; | 
 |     if (GetParam() == | 
 |         FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_OTHER_THREAD) { | 
 |       Thread::Options options; | 
 |       options.message_pump_type = MessagePumpType::IO; | 
 |       ASSERT_TRUE(other_thread_.StartWithOptions(std::move(options))); | 
 |       file_descriptor_watcher_ = | 
 |           std::make_unique<FileDescriptorWatcher>(other_thread_.task_runner()); | 
 |     } | 
 |   } | 
 |  | 
 |   void TearDown() override { | 
 |     if (GetParam() == | 
 |             FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD && | 
 |         task_environment_) { | 
 |       // Allow the delete task posted by the Controller's destructor to run. | 
 |       base::RunLoop().RunUntilIdle(); | 
 |     } | 
 |  | 
 |     // Ensure that OtherThread is done processing before closing fds. | 
 |     other_thread_.Stop(); | 
 |  | 
 |     EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[0]))); | 
 |     EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds_[1]))); | 
 |  | 
 |     // These fds may be destroyed during tests. | 
 |     if (pipe_fds2_[0] != -1) { | 
 |       EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds2_[0]))); | 
 |     } | 
 |     if (pipe_fds2_[1] != -1) { | 
 |       EXPECT_EQ(0, IGNORE_EINTR(close(pipe_fds2_[1]))); | 
 |     } | 
 |   } | 
 |  | 
 |  protected: | 
 |   int read_file_descriptor() const { return pipe_fds_[0]; } | 
 |   int write_file_descriptor() const { return pipe_fds_[1]; } | 
 |  | 
 |   int read_file_descriptor2() const { return pipe_fds2_[0]; } | 
 |   int write_file_descriptor2() const { return pipe_fds2_[1]; } | 
 |   int& read_file_descriptor2_ref() { return pipe_fds2_[0]; } | 
 |   int& write_file_descriptor2_ref() { return pipe_fds2_[1]; } | 
 |  | 
 |   // Waits for a short delay and run pending tasks. | 
 |   void WaitAndRunPendingTasks() { | 
 |     PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | 
 |     RunLoop().RunUntilIdle(); | 
 |   } | 
 |  | 
 |   // Registers ReadableCallback() to be called on |mock_| when | 
 |   // read_file_descriptor() is readable without blocking. | 
 |   std::unique_ptr<FileDescriptorWatcher::Controller> WatchReadable() { | 
 |     std::unique_ptr<FileDescriptorWatcher::Controller> controller = | 
 |         FileDescriptorWatcher::WatchReadable( | 
 |             read_file_descriptor(), | 
 |             BindRepeating(&Mock::ReadableCallback, Unretained(&mock_))); | 
 |     EXPECT_TRUE(controller); | 
 |  | 
 |     // Unless read_file_descriptor() was readable before the callback was | 
 |     // registered, this shouldn't do anything. | 
 |     WaitAndRunPendingTasks(); | 
 |  | 
 |     return controller; | 
 |   } | 
 |  | 
 |   // Registers WritableCallback() to be called on |mock_| when | 
 |   // write_file_descriptor() is writable without blocking. | 
 |   std::unique_ptr<FileDescriptorWatcher::Controller> WatchWritable() { | 
 |     std::unique_ptr<FileDescriptorWatcher::Controller> controller = | 
 |         FileDescriptorWatcher::WatchWritable( | 
 |             write_file_descriptor(), | 
 |             BindRepeating(&Mock::WritableCallback, Unretained(&mock_))); | 
 |     EXPECT_TRUE(controller); | 
 |     return controller; | 
 |   } | 
 |  | 
 |   // Registers ReadableCallback2() to be called on |mock_| when | 
 |   // read_file_descriptor2() is readable without blocking. | 
 |   std::unique_ptr<FileDescriptorWatcher::Controller> WatchReadable2() { | 
 |     std::unique_ptr<FileDescriptorWatcher::Controller> controller = | 
 |         FileDescriptorWatcher::WatchReadable( | 
 |             read_file_descriptor2(), | 
 |             BindRepeating(&Mock::ReadableCallback2, Unretained(&mock_))); | 
 |     EXPECT_TRUE(controller); | 
 |  | 
 |     // Unless read_file_descriptor() was readable before the callback was | 
 |     // registered, this shouldn't do anything. | 
 |     WaitAndRunPendingTasks(); | 
 |  | 
 |     return controller; | 
 |   } | 
 |  | 
 |   // Registers WritableCallback2() to be called on |mock_| when | 
 |   // write_file_descriptor2() is writable without blocking. | 
 |   std::unique_ptr<FileDescriptorWatcher::Controller> WatchWritable2() { | 
 |     std::unique_ptr<FileDescriptorWatcher::Controller> controller = | 
 |         FileDescriptorWatcher::WatchWritable( | 
 |             write_file_descriptor2(), | 
 |             BindRepeating(&Mock::WritableCallback2, Unretained(&mock_))); | 
 |     EXPECT_TRUE(controller); | 
 |     return controller; | 
 |   } | 
 |  | 
 |   void WriteByte() { | 
 |     constexpr char kByte = '!'; | 
 |     ASSERT_TRUE(WriteFileDescriptor(write_file_descriptor(), | 
 |                                     byte_span_from_ref(kByte))); | 
 |   } | 
 |  | 
 |   void ReadByte() { | 
 |     // This is always called in ReadableCallback(), which should run on the main | 
 |     // thread. | 
 |     EXPECT_TRUE(thread_checker_.CalledOnValidThread()); | 
 |  | 
 |     char buffer; | 
 |     ASSERT_TRUE(ReadFromFD(read_file_descriptor(), span_from_ref(buffer))); | 
 |   } | 
 |  | 
 |   void WriteByte2() { | 
 |     constexpr char kByte = '!'; | 
 |     ASSERT_TRUE(WriteFileDescriptor(write_file_descriptor2(), | 
 |                                     byte_span_from_ref(kByte))); | 
 |   } | 
 |  | 
 |   void ReadByte2() { | 
 |     // This is always called in ReadableCallback2(), which should run on the | 
 |     // main thread. | 
 |     EXPECT_TRUE(thread_checker_.CalledOnValidThread()); | 
 |  | 
 |     char buffer; | 
 |     ASSERT_TRUE(ReadFromFD(read_file_descriptor2(), span_from_ref(buffer))); | 
 |   } | 
 |  | 
 |   void CloseWriteFd2() { | 
 |     ASSERT_EQ(0, IGNORE_EINTR(close(write_file_descriptor2()))); | 
 |     write_file_descriptor2_ref() = -1; | 
 |   } | 
 |  | 
 |   // Mock on wich callbacks are invoked. | 
 |   testing::StrictMock<Mock> mock_; | 
 |  | 
 |   // Task environment bound to the main thread. | 
 |   std::unique_ptr<test::TaskEnvironment> task_environment_; | 
 |  | 
 |   // Thread running an IO message pump. Used when the test type is | 
 |   // MESSAGE_PUMP_FOR_IO_ON_OTHER_THREAD. | 
 |   Thread other_thread_; | 
 |  | 
 |  private: | 
 |   // Used to listen for file descriptor events on |other_thread_|. The scoped | 
 |   // task environment implements a watcher for the main thread case. | 
 |   std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_; | 
 |  | 
 |   // Watched file descriptors. | 
 |   int pipe_fds_[2]; | 
 |   int pipe_fds2_[2]; | 
 |  | 
 |   // Used to verify that callbacks run on the thread on which they are | 
 |   // registered. | 
 |   ThreadCheckerImpl thread_checker_; | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | TEST_P(FileDescriptorWatcherTest, WatchWritable) { | 
 |   auto controller = WatchWritable(); | 
 |  | 
 |   // The write end of a newly created pipe is immediately writable. | 
 |   RunLoop run_loop; | 
 |   EXPECT_CALL(mock_, WritableCallback()) | 
 |       .WillOnce(testing::Invoke(&run_loop, &RunLoop::Quit)); | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST_P(FileDescriptorWatcherTest, WatchReadableOneByte) { | 
 |   auto controller = WatchReadable(); | 
 |  | 
 |   // Write 1 byte to the pipe, making it readable without blocking. Expect one | 
 |   // call to ReadableCallback() which will read 1 byte from the pipe. | 
 |   WriteByte(); | 
 |   RunLoop run_loop; | 
 |   EXPECT_CALL(mock_, ReadableCallback()) | 
 |       .WillOnce(testing::Invoke([this, &run_loop] { | 
 |         ReadByte(); | 
 |         run_loop.Quit(); | 
 |       })); | 
 |   run_loop.Run(); | 
 |   testing::Mock::VerifyAndClear(&mock_); | 
 |  | 
 |   // No more call to ReadableCallback() is expected. | 
 |   WaitAndRunPendingTasks(); | 
 | } | 
 |  | 
 | TEST_P(FileDescriptorWatcherTest, WatchReadableTwoBytes) { | 
 |   auto controller = WatchReadable(); | 
 |  | 
 |   // Write 2 bytes to the pipe. Expect two calls to ReadableCallback() which | 
 |   // will each read 1 byte from the pipe. | 
 |   WriteByte(); | 
 |   WriteByte(); | 
 |   RunLoop run_loop; | 
 |   EXPECT_CALL(mock_, ReadableCallback()) | 
 |       .WillOnce(testing::Invoke([this] { ReadByte(); })) | 
 |       .WillOnce(testing::Invoke([this, &run_loop] { | 
 |         ReadByte(); | 
 |         run_loop.Quit(); | 
 |       })); | 
 |   run_loop.Run(); | 
 |   testing::Mock::VerifyAndClear(&mock_); | 
 |  | 
 |   // No more call to ReadableCallback() is expected. | 
 |   WaitAndRunPendingTasks(); | 
 | } | 
 |  | 
 | TEST_P(FileDescriptorWatcherTest, WatchReadableByteWrittenFromCallback) { | 
 |   auto controller = WatchReadable(); | 
 |  | 
 |   // Write 1 byte to the pipe. Expect one call to ReadableCallback() from which | 
 |   // 1 byte is read and 1 byte is written to the pipe. Then, expect another call | 
 |   // to ReadableCallback() from which the remaining byte is read from the pipe. | 
 |   WriteByte(); | 
 |   RunLoop run_loop; | 
 |   EXPECT_CALL(mock_, ReadableCallback()) | 
 |       .WillOnce(testing::Invoke([this] { | 
 |         ReadByte(); | 
 |         WriteByte(); | 
 |       })) | 
 |       .WillOnce(testing::Invoke([this, &run_loop] { | 
 |         ReadByte(); | 
 |         run_loop.Quit(); | 
 |       })); | 
 |   run_loop.Run(); | 
 |   testing::Mock::VerifyAndClear(&mock_); | 
 |  | 
 |   // No more call to ReadableCallback() is expected. | 
 |   WaitAndRunPendingTasks(); | 
 | } | 
 |  | 
 | TEST_P(FileDescriptorWatcherTest, DeleteControllerFromCallback) { | 
 |   auto controller = WatchReadable(); | 
 |  | 
 |   // Write 1 byte to the pipe. Expect one call to ReadableCallback() from which | 
 |   // |controller| is deleted. | 
 |   WriteByte(); | 
 |   RunLoop run_loop; | 
 |   EXPECT_CALL(mock_, ReadableCallback()) | 
 |       .WillOnce(testing::Invoke([&run_loop, &controller] { | 
 |         controller = nullptr; | 
 |         run_loop.Quit(); | 
 |       })); | 
 |   run_loop.Run(); | 
 |   testing::Mock::VerifyAndClear(&mock_); | 
 |  | 
 |   // Since |controller| has been deleted, no call to ReadableCallback() is | 
 |   // expected even though the pipe is still readable without blocking. | 
 |   WaitAndRunPendingTasks(); | 
 | } | 
 |  | 
 | TEST_P(FileDescriptorWatcherTest, | 
 |        DeleteControllerBeforeFileDescriptorReadable) { | 
 |   auto controller = WatchReadable(); | 
 |  | 
 |   // Cancel the watch. | 
 |   controller = nullptr; | 
 |  | 
 |   // Write 1 byte to the pipe to make it readable without blocking. | 
 |   WriteByte(); | 
 |  | 
 |   // No call to ReadableCallback() is expected. | 
 |   WaitAndRunPendingTasks(); | 
 | } | 
 |  | 
 | TEST_P(FileDescriptorWatcherTest, DeleteControllerAfterFileDescriptorReadable) { | 
 |   auto controller = WatchReadable(); | 
 |  | 
 |   // Write 1 byte to the pipe to make it readable without blocking. | 
 |   WriteByte(); | 
 |  | 
 |   // Cancel the watch. | 
 |   controller = nullptr; | 
 |  | 
 |   // No call to ReadableCallback() is expected. | 
 |   WaitAndRunPendingTasks(); | 
 | } | 
 |  | 
 | TEST_P(FileDescriptorWatcherTest, DeleteControllerAfterDeleteMessagePumpForIO) { | 
 |   auto controller = WatchReadable(); | 
 |  | 
 |   // Delete the task environment. | 
 |   if (GetParam() == | 
 |       FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD) { | 
 |     task_environment_.reset(); | 
 |   } else { | 
 |     other_thread_.Stop(); | 
 |   } | 
 |  | 
 |   // Deleting |controller| shouldn't crash even though that causes a task to be | 
 |   // posted to the message pump thread. | 
 |   controller = nullptr; | 
 | } | 
 |  | 
 | TEST_P(FileDescriptorWatcherTest, | 
 |        WatchReadableOneByteAndWatchReadableTwoBytesOnFd2ClosedInTheMiddle) { | 
 |   auto controller = WatchReadable(); | 
 |   auto controller2 = WatchReadable2(); | 
 |  | 
 |   // Write 1 byte to the pipe 1 and 2 bytes to the pipe 2. The write fd of the | 
 |   // pipe 2 will be closed before finishing to read 2 bytes. Expect 1 call to | 
 |   // ReadableCallback() and 2 calls to ReadableCallback2() which will each read | 
 |   // 1 byte from the pipes. | 
 |   WriteByte(); | 
 |   WriteByte2(); | 
 |   WriteByte2(); | 
 |  | 
 |   RunLoop run_loop; | 
 |   EXPECT_CALL(mock_, ReadableCallback()) | 
 |       .WillOnce(testing::Invoke([this, &controller] { | 
 |         ReadByte(); | 
 |         CloseWriteFd2(); | 
 |         controller.reset(); | 
 |       })); | 
 |   EXPECT_CALL(mock_, ReadableCallback2()) | 
 |       .WillOnce(testing::Invoke([this] { ReadByte2(); })) | 
 |       .WillOnce(testing::Invoke([this, &controller2, &run_loop] { | 
 |         ReadByte2(); | 
 |         controller2.reset(); | 
 |         run_loop.Quit(); | 
 |       })); | 
 |   run_loop.Run(); | 
 |   testing::Mock::VerifyAndClear(&mock_); | 
 |  | 
 |   // No more call to ReadableCallback() or ReadableCallback2() is expected. | 
 |   WaitAndRunPendingTasks(); | 
 | } | 
 |  | 
 | INSTANTIATE_TEST_SUITE_P( | 
 |     MessagePumpForIOOnMainThread, | 
 |     FileDescriptorWatcherTest, | 
 |     ::testing::Values( | 
 |         FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_MAIN_THREAD)); | 
 | INSTANTIATE_TEST_SUITE_P( | 
 |     MessagePumpForIOOnOtherThread, | 
 |     FileDescriptorWatcherTest, | 
 |     ::testing::Values( | 
 |         FileDescriptorWatcherTestType::MESSAGE_PUMP_FOR_IO_ON_OTHER_THREAD)); | 
 |  | 
 | }  // namespace base |