1 // Copyright 2016 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/public/cpp/system/watcher.h" 6 7 #include <memory> 8 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/run_loop.h" 13 #include "base/threading/thread_task_runner_handle.h" 14 #include "mojo/public/c/system/types.h" 15 #include "mojo/public/cpp/system/message_pipe.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 namespace mojo { 19 namespace { 20 21 template <typename Handler> 22 void RunResultHandler(Handler f, MojoResult result) { f(result); } 23 24 template <typename Handler> 25 Watcher::ReadyCallback OnReady(Handler f) { 26 return base::Bind(&RunResultHandler<Handler>, f); 27 } 28 29 Watcher::ReadyCallback NotReached() { 30 return OnReady([] (MojoResult) { NOTREACHED(); }); 31 } 32 33 class WatcherTest : public testing::Test { 34 public: 35 WatcherTest() {} 36 ~WatcherTest() override {} 37 38 void SetUp() override { 39 message_loop_.reset(new base::MessageLoop); 40 } 41 42 void TearDown() override { 43 message_loop_.reset(); 44 } 45 46 protected: 47 std::unique_ptr<base::MessageLoop> message_loop_; 48 }; 49 50 TEST_F(WatcherTest, WatchBasic) { 51 ScopedMessagePipeHandle a, b; 52 CreateMessagePipe(nullptr, &a, &b); 53 54 bool notified = false; 55 base::RunLoop run_loop; 56 Watcher b_watcher; 57 EXPECT_EQ(MOJO_RESULT_OK, 58 b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, 59 OnReady([&] (MojoResult result) { 60 EXPECT_EQ(MOJO_RESULT_OK, result); 61 notified = true; 62 run_loop.Quit(); 63 }))); 64 EXPECT_TRUE(b_watcher.IsWatching()); 65 66 EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, 67 MOJO_WRITE_MESSAGE_FLAG_NONE)); 68 run_loop.Run(); 69 EXPECT_TRUE(notified); 70 71 b_watcher.Cancel(); 72 } 73 74 TEST_F(WatcherTest, WatchUnsatisfiable) { 75 ScopedMessagePipeHandle a, b; 76 CreateMessagePipe(nullptr, &a, &b); 77 a.reset(); 78 79 Watcher b_watcher; 80 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, 81 b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, 82 NotReached())); 83 EXPECT_FALSE(b_watcher.IsWatching()); 84 } 85 86 TEST_F(WatcherTest, WatchInvalidHandle) { 87 ScopedMessagePipeHandle a, b; 88 CreateMessagePipe(nullptr, &a, &b); 89 a.reset(); 90 b.reset(); 91 92 Watcher b_watcher; 93 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, 94 b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, 95 NotReached())); 96 EXPECT_FALSE(b_watcher.IsWatching()); 97 } 98 99 TEST_F(WatcherTest, Cancel) { 100 ScopedMessagePipeHandle a, b; 101 CreateMessagePipe(nullptr, &a, &b); 102 103 base::RunLoop run_loop; 104 Watcher b_watcher; 105 EXPECT_EQ(MOJO_RESULT_OK, 106 b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, 107 NotReached())); 108 EXPECT_TRUE(b_watcher.IsWatching()); 109 b_watcher.Cancel(); 110 EXPECT_FALSE(b_watcher.IsWatching()); 111 112 // This should never trigger the watcher. 113 EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, 114 MOJO_WRITE_MESSAGE_FLAG_NONE)); 115 116 base::ThreadTaskRunnerHandle::Get()->PostTask( 117 FROM_HERE, run_loop.QuitClosure()); 118 run_loop.Run(); 119 } 120 121 TEST_F(WatcherTest, CancelOnClose) { 122 ScopedMessagePipeHandle a, b; 123 CreateMessagePipe(nullptr, &a, &b); 124 125 base::RunLoop run_loop; 126 Watcher b_watcher; 127 EXPECT_EQ(MOJO_RESULT_OK, 128 b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, 129 OnReady([&] (MojoResult result) { 130 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); 131 run_loop.Quit(); 132 }))); 133 EXPECT_TRUE(b_watcher.IsWatching()); 134 135 // This should trigger the watcher above. 136 b.reset(); 137 138 run_loop.Run(); 139 140 EXPECT_FALSE(b_watcher.IsWatching()); 141 } 142 143 TEST_F(WatcherTest, CancelOnDestruction) { 144 ScopedMessagePipeHandle a, b; 145 CreateMessagePipe(nullptr, &a, &b); 146 base::RunLoop run_loop; 147 { 148 Watcher b_watcher; 149 EXPECT_EQ(MOJO_RESULT_OK, 150 b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, 151 NotReached())); 152 EXPECT_TRUE(b_watcher.IsWatching()); 153 154 // |b_watcher| should be cancelled when it goes out of scope. 155 } 156 157 // This should never trigger the watcher above. 158 EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, 159 MOJO_WRITE_MESSAGE_FLAG_NONE)); 160 base::ThreadTaskRunnerHandle::Get()->PostTask( 161 FROM_HERE, run_loop.QuitClosure()); 162 run_loop.Run(); 163 } 164 165 TEST_F(WatcherTest, NotifyOnMessageLoopDestruction) { 166 ScopedMessagePipeHandle a, b; 167 CreateMessagePipe(nullptr, &a, &b); 168 169 bool notified = false; 170 Watcher b_watcher; 171 EXPECT_EQ(MOJO_RESULT_OK, 172 b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, 173 OnReady([&] (MojoResult result) { 174 EXPECT_EQ(MOJO_RESULT_ABORTED, result); 175 notified = true; 176 }))); 177 EXPECT_TRUE(b_watcher.IsWatching()); 178 179 message_loop_.reset(); 180 181 EXPECT_TRUE(notified); 182 183 EXPECT_TRUE(b_watcher.IsWatching()); 184 b_watcher.Cancel(); 185 } 186 187 TEST_F(WatcherTest, CloseAndCancel) { 188 ScopedMessagePipeHandle a, b; 189 CreateMessagePipe(nullptr, &a, &b); 190 191 Watcher b_watcher; 192 EXPECT_EQ(MOJO_RESULT_OK, 193 b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, 194 OnReady([](MojoResult result) { FAIL(); }))); 195 EXPECT_TRUE(b_watcher.IsWatching()); 196 197 // This should trigger the watcher above... 198 b.reset(); 199 // ...but the watcher is cancelled first. 200 b_watcher.Cancel(); 201 202 EXPECT_FALSE(b_watcher.IsWatching()); 203 204 base::RunLoop().RunUntilIdle(); 205 } 206 207 } // namespace 208 } // namespace mojo 209