Index: mojo/edk/system/watch_unittest.cc |
diff --git a/mojo/edk/system/watch_unittest.cc b/mojo/edk/system/watch_unittest.cc |
deleted file mode 100644 |
index ec28d94f8058f25d40abcb88bcebbc1161364bed..0000000000000000000000000000000000000000 |
--- a/mojo/edk/system/watch_unittest.cc |
+++ /dev/null |
@@ -1,480 +0,0 @@ |
-// Copyright 2016 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include <functional> |
- |
-#include "base/macros.h" |
-#include "base/memory/ref_counted.h" |
-#include "base/message_loop/message_loop.h" |
-#include "base/run_loop.h" |
-#include "base/single_thread_task_runner.h" |
-#include "base/threading/thread_task_runner_handle.h" |
-#include "mojo/edk/system/request_context.h" |
-#include "mojo/edk/test/mojo_test_base.h" |
-#include "mojo/public/c/system/functions.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-namespace mojo { |
-namespace edk { |
-namespace { |
- |
-void IgnoreResult(uintptr_t context, |
- MojoResult result, |
- MojoHandleSignalsState signals, |
- MojoWatchNotificationFlags flags) { |
-} |
- |
-// A test helper class for watching a handle. The WatchHelper instance is used |
-// as a watch context for a single watch callback. |
-class WatchHelper { |
- public: |
- using Callback = |
- std::function<void(MojoResult result, MojoHandleSignalsState state)>; |
- |
- WatchHelper() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {} |
- ~WatchHelper() { |
- CHECK(!watching_); |
- } |
- |
- void Watch(MojoHandle handle, |
- MojoHandleSignals signals, |
- const Callback& callback) { |
- CHECK(!watching_); |
- |
- handle_ = handle; |
- callback_ = callback; |
- watching_ = true; |
- CHECK_EQ(MOJO_RESULT_OK, MojoWatch(handle_, signals, &WatchHelper::OnNotify, |
- reinterpret_cast<uintptr_t>(this))); |
- } |
- |
- bool is_watching() const { return watching_; } |
- |
- void Cancel() { |
- CHECK_EQ(MOJO_RESULT_OK, |
- MojoCancelWatch(handle_, reinterpret_cast<uintptr_t>(this))); |
- CHECK(watching_); |
- watching_ = false; |
- } |
- |
- private: |
- static void OnNotify(uintptr_t context, |
- MojoResult result, |
- MojoHandleSignalsState state, |
- MojoWatchNotificationFlags flags) { |
- WatchHelper* watcher = reinterpret_cast<WatchHelper*>(context); |
- watcher->task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&NotifyOnMainThread, context, result, state, flags)); |
- } |
- |
- static void NotifyOnMainThread(uintptr_t context, |
- MojoResult result, |
- MojoHandleSignalsState state, |
- MojoWatchNotificationFlags flags) { |
- WatchHelper* watcher = reinterpret_cast<WatchHelper*>(context); |
- CHECK(watcher->watching_); |
- if (result == MOJO_RESULT_CANCELLED) |
- watcher->watching_ = false; |
- watcher->callback_(result, state); |
- } |
- |
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
- bool watching_ = false; |
- MojoHandle handle_; |
- Callback callback_; |
- |
- DISALLOW_COPY_AND_ASSIGN(WatchHelper); |
-}; |
- |
-class WatchTest : public test::MojoTestBase { |
- public: |
- WatchTest() {} |
- ~WatchTest() override {} |
- |
- protected: |
- |
- private: |
- base::MessageLoop message_loop_; |
- |
- DISALLOW_COPY_AND_ASSIGN(WatchTest); |
-}; |
- |
-TEST_F(WatchTest, NotifyBasic) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- base::RunLoop loop; |
- WatchHelper b_watcher; |
- b_watcher.Watch( |
- b, MOJO_HANDLE_SIGNAL_READABLE, |
- [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_OK, result); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |
- state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |
- EXPECT_TRUE(b_watcher.is_watching()); |
- loop.Quit(); |
- }); |
- |
- WriteMessage(a, "Hello!"); |
- loop.Run(); |
- |
- EXPECT_TRUE(b_watcher.is_watching()); |
- b_watcher.Cancel(); |
- |
- CloseHandle(a); |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, NotifyUnsatisfiable) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- base::RunLoop loop; |
- WatchHelper b_watcher; |
- b_watcher.Watch( |
- b, MOJO_HANDLE_SIGNAL_READABLE, |
- [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); |
- EXPECT_EQ(0u, |
- state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |
- EXPECT_EQ(0u, |
- state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); |
- EXPECT_TRUE(b_watcher.is_watching()); |
- loop.Quit(); |
- }); |
- |
- CloseHandle(a); |
- loop.Run(); |
- |
- b_watcher.Cancel(); |
- |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, NotifyCancellation) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- base::RunLoop loop; |
- WatchHelper b_watcher; |
- b_watcher.Watch( |
- b, MOJO_HANDLE_SIGNAL_READABLE, |
- [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_CANCELLED, result); |
- EXPECT_EQ(0u, state.satisfied_signals); |
- EXPECT_EQ(0u, state.satisfiable_signals); |
- EXPECT_FALSE(b_watcher.is_watching()); |
- loop.Quit(); |
- }); |
- |
- CloseHandle(b); |
- loop.Run(); |
- |
- CloseHandle(a); |
-} |
- |
-TEST_F(WatchTest, InvalidArguemnts) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- uintptr_t context = reinterpret_cast<uintptr_t>(this); |
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, |
- &IgnoreResult, context)); |
- |
- // Can't cancel a watch that doesn't exist. |
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(a, ~context)); |
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(b, context)); |
- |
- CloseHandle(a); |
- CloseHandle(b); |
- |
- // Can't watch a handle that doesn't exist. |
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, |
- MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); |
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, |
- MojoWatch(b, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); |
-} |
- |
-TEST_F(WatchTest, NoDuplicateContext) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- // Try to add the same watch twice; should fail. |
- uintptr_t context = reinterpret_cast<uintptr_t>(this); |
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, |
- &IgnoreResult, context)); |
- EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
- MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); |
- |
- // Cancel and add it again; should be OK. |
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(a, context)); |
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, |
- &IgnoreResult, context)); |
- |
- CloseHandle(a); |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, MultipleWatches) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- // Add multiple watchers to |b| and see that they are both notified by a |
- // single write to |a|. |
- base::RunLoop loop; |
- int expected_notifications = 2; |
- auto on_readable = [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_OK, result); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |
- state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |
- EXPECT_GT(expected_notifications, 0); |
- if (--expected_notifications == 0) |
- loop.Quit(); |
- }; |
- WatchHelper watcher1; |
- WatchHelper watcher2; |
- watcher1.Watch(b, MOJO_HANDLE_SIGNAL_READABLE, on_readable); |
- watcher2.Watch(b, MOJO_HANDLE_SIGNAL_READABLE, on_readable); |
- |
- WriteMessage(a, "Ping!"); |
- loop.Run(); |
- |
- watcher1.Cancel(); |
- watcher2.Cancel(); |
- |
- CloseHandle(a); |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, WatchWhileSatisfied) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- // Write to |a| and then start watching |b|. The callback should be invoked |
- // synchronously. |
- WriteMessage(a, "hey"); |
- bool signaled = false; |
- WatchHelper b_watcher; |
- base::RunLoop loop; |
- b_watcher.Watch( |
- b, MOJO_HANDLE_SIGNAL_READABLE, |
- [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_OK, result); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |
- state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |
- signaled = true; |
- loop.Quit(); |
- }); |
- loop.Run(); |
- EXPECT_TRUE(signaled); |
- b_watcher.Cancel(); |
- |
- CloseHandle(a); |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, WatchWhileUnsatisfiable) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- // Close |a| and then try to watch |b|. MojoWatch() should fail. |
- CloseHandle(a); |
- uintptr_t context = reinterpret_cast<uintptr_t>(this); |
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
- MojoWatch(b, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); |
- |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, RespondFromCallback) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- // Watch |a| and |b|. Write to |a|, then write to |b| from within the callback |
- // which notifies it of the available message. |
- const std::string kTestMessage = "hello worlds."; |
- base::RunLoop loop; |
- WatchHelper b_watcher; |
- b_watcher.Watch( |
- b, MOJO_HANDLE_SIGNAL_READABLE, |
- [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_OK, result); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |
- state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |
- EXPECT_TRUE(b_watcher.is_watching()); |
- |
- // Echo a's message back to it. |
- WriteMessage(b, ReadMessage(b)); |
- }); |
- |
- WatchHelper a_watcher; |
- a_watcher.Watch( |
- a, MOJO_HANDLE_SIGNAL_READABLE, |
- [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_OK, result); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |
- state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |
- EXPECT_TRUE(a_watcher.is_watching()); |
- |
- // Expect to receive back the message that was originally sent to |b|. |
- EXPECT_EQ(kTestMessage, ReadMessage(a)); |
- |
- loop.Quit(); |
- }); |
- |
- WriteMessage(a, kTestMessage); |
- loop.Run(); |
- |
- a_watcher.Cancel(); |
- b_watcher.Cancel(); |
- |
- CloseHandle(a); |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, WatchDataPipeConsumer) { |
- MojoHandle a, b; |
- CreateDataPipe(&a, &b, 64); |
- |
- base::RunLoop loop; |
- WatchHelper b_watcher; |
- b_watcher.Watch( |
- b, MOJO_HANDLE_SIGNAL_READABLE, |
- [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_OK, result); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |
- state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |
- EXPECT_TRUE(b_watcher.is_watching()); |
- loop.Quit(); |
- }); |
- |
- WriteData(a, "Hello!"); |
- loop.Run(); |
- |
- EXPECT_TRUE(b_watcher.is_watching()); |
- b_watcher.Cancel(); |
- |
- CloseHandle(a); |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, WatchDataPipeProducer) { |
- MojoHandle a, b; |
- CreateDataPipe(&a, &b, 8); |
- |
- // Fill the pipe to capacity so writes will block. |
- WriteData(a, "xxxxxxxx"); |
- |
- base::RunLoop loop; |
- WatchHelper a_watcher; |
- a_watcher.Watch( |
- a, MOJO_HANDLE_SIGNAL_WRITABLE, |
- [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_OK, result); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, |
- state.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); |
- EXPECT_TRUE(a_watcher.is_watching()); |
- loop.Quit(); |
- }); |
- |
- EXPECT_EQ("xxxxxxxx", ReadData(b, 8)); |
- loop.Run(); |
- |
- EXPECT_TRUE(a_watcher.is_watching()); |
- a_watcher.Cancel(); |
- |
- CloseHandle(a); |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, WakeUpSelfWithinWatchCallback) { |
- MojoHandle a, b; |
- CreateMessagePipe(&a, &b); |
- |
- int expected_notifications = 2; |
- base::RunLoop loop; |
- WatchHelper b_watcher; |
- b_watcher.Watch( |
- b, MOJO_HANDLE_SIGNAL_READABLE, |
- [&] (MojoResult result, MojoHandleSignalsState state) { |
- EXPECT_EQ(MOJO_RESULT_OK, result); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |
- state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |
- EXPECT_TRUE(b_watcher.is_watching()); |
- if (--expected_notifications == 0) { |
- loop.Quit(); |
- } else { |
- // Trigger b's watch again from within this callback. This should be |
- // safe to do. |
- WriteMessage(a, "hey"); |
- } |
- }); |
- |
- WriteMessage(a, "hey hey hey"); |
- loop.Run(); |
- |
- b_watcher.Cancel(); |
- |
- CloseHandle(a); |
- CloseHandle(b); |
-} |
- |
-TEST_F(WatchTest, NestedCancellation) { |
- // Verifies that cancellations in nested system request contexts preempt |
- // other notifications for the same watcher. This tests against the condition |
- // hit by http://crbug.com/622298. |
- |
- MojoHandle a, b, c, d; |
- CreateMessagePipe(&a, &b); |
- CreateMessagePipe(&c, &d); |
- |
- base::RunLoop loop; |
- bool a_watcher_run = false; |
- WatchHelper a_watcher; |
- a_watcher.Watch( |
- a, MOJO_HANDLE_SIGNAL_READABLE, |
- [&](MojoResult result, MojoHandleSignalsState state) { |
- a_watcher_run = true; |
- }); |
- |
- WatchHelper c_watcher; |
- c_watcher.Watch( |
- c, MOJO_HANDLE_SIGNAL_READABLE, |
- [&](MojoResult result, MojoHandleSignalsState state) { |
- // This will trigger a notification on |a_watcher| above to be executed |
- // once this handler finishes running... |
- CloseHandle(b); |
- |
- // ...but this should prevent that notification from dispatching because |
- // |a_watcher| is now cancelled. |
- a_watcher.Cancel(); |
- |
- loop.Quit(); |
- }); |
- |
- { |
- // Force "system" notifications for the synchronous behavior required to |
- // test this case. |
- mojo::edk::RequestContext request_context( |
- mojo::edk::RequestContext::Source::SYSTEM); |
- |
- // Trigger the |c_watcher| callback above. |
- CloseHandle(d); |
- } |
- |
- loop.Run(); |
- |
- EXPECT_FALSE(a_watcher.is_watching()); |
- EXPECT_FALSE(a_watcher_run); |
- |
- c_watcher.Cancel(); |
- |
- CloseHandle(a); |
- CloseHandle(c); |
-} |
- |
-} // namespace |
-} // namespace edk |
-} // namespace mojo |