Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1137)

Unified Diff: mojo/edk/system/watch_unittest.cc

Issue 1748503002: [mojo-edk] Add MojoWatch and MojoCancelWatch APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: revert RequestContext usage, nits Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mojo/edk/system/request_context.cc ('k') | mojo/edk/system/watcher.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojo/edk/system/watch_unittest.cc
diff --git a/mojo/edk/system/watch_unittest.cc b/mojo/edk/system/watch_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fd0c13d88cb9e1d0a43821edbb9dde361549cbfd
--- /dev/null
+++ b/mojo/edk/system/watch_unittest.cc
@@ -0,0 +1,374 @@
+// 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/message_loop/message_loop.h"
+#include "base/run_loop.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) {
+}
+
+// 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() {}
+ ~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) {
+ WatchHelper* watcher = reinterpret_cast<WatchHelper*>(context);
+ CHECK(watcher->watching_);
+ if (result == MOJO_RESULT_CANCELLED)
+ watcher->watching_ = false;
+ watcher->callback_(result, state);
+ }
+
+ 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;
+ 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;
+ });
+ 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);
+}
+
+} // namespace
+} // namespace edk
+} // namespace mojo
« no previous file with comments | « mojo/edk/system/request_context.cc ('k') | mojo/edk/system/watcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698