summaryrefslogtreecommitdiffstats
path: root/xpcom/tests/gtest/TestStateMirroring.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/tests/gtest/TestStateMirroring.cpp')
-rw-r--r--xpcom/tests/gtest/TestStateMirroring.cpp121
1 files changed, 121 insertions, 0 deletions
diff --git a/xpcom/tests/gtest/TestStateMirroring.cpp b/xpcom/tests/gtest/TestStateMirroring.cpp
new file mode 100644
index 0000000000..e96ecb9a18
--- /dev/null
+++ b/xpcom/tests/gtest/TestStateMirroring.cpp
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/gtest/WaitFor.h"
+#include "mozilla/SharedThreadPool.h"
+#include "mozilla/StateMirroring.h"
+#include "mozilla/SynchronizedEventQueue.h"
+#include "mozilla/TaskQueue.h"
+#include "mozilla/Unused.h"
+#include "nsISupportsImpl.h"
+#include "nsThreadUtils.h"
+#include "VideoUtils.h"
+
+namespace TestStateMirroring {
+
+using namespace mozilla;
+
+class StateMirroringTest : public ::testing::Test {
+ public:
+ using ValueType = int;
+ using Promise = MozPromise<ValueType, bool, /*IsExclusive =*/true>;
+
+ StateMirroringTest()
+ : mTarget(
+ TaskQueue::Create(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
+ "TestStateMirroring",
+ /*aSupportsTailDispatch =*/true)),
+ mCanonical(AbstractThread::GetCurrent(), 0, "TestCanonical"),
+ mMirror(mTarget, 0, "TestMirror") {}
+
+ void TearDown() override {
+ mTarget->BeginShutdown();
+ mTarget->AwaitShutdownAndIdle();
+
+ // Make sure to run any events just dispatched from mTarget to main thread
+ // before continuing on to the next test.
+ NS_ProcessPendingEvents(nullptr);
+ }
+
+ RefPtr<Promise> ReadMirrorAsync() {
+ return InvokeAsync(mTarget, __func__, [&] {
+ return Promise::CreateAndResolve(mMirror, "ReadMirrorAsync::Resolve");
+ });
+ }
+
+ protected:
+ const RefPtr<TaskQueue> mTarget;
+ Canonical<int> mCanonical;
+ Mirror<int> mMirror;
+};
+
+TEST_F(StateMirroringTest, MirrorInitiatedEventOrdering) {
+ // Note that this requires the tail dispatcher, which is not available until
+ // we are processing events.
+ ASSERT_FALSE(AbstractThread::GetCurrent()->IsTailDispatcherAvailable());
+
+ MOZ_ALWAYS_SUCCEEDS(NS_DispatchAndSpinEventLoopUntilComplete(
+ "NeedTailDispatcher"_ns, GetCurrentSerialEventTarget(),
+ NS_NewRunnableFunction(__func__, [&] {
+ ASSERT_TRUE(AbstractThread::GetCurrent()->IsTailDispatcherAvailable());
+
+ RefPtr<Promise> mirrorPromise;
+
+ // This will ensure the tail dispatcher fires to dispatch the group
+ // runnable holding the Mirror::Connect task, before we continue the
+ // test.
+ MOZ_ALWAYS_SUCCEEDS(NS_DispatchAndSpinEventLoopUntilComplete(
+ "NeedTailDispatcher"_ns, GetCurrentSerialEventTarget(),
+ NS_NewRunnableFunction(__func__, [&] {
+ // Show that mirroring does not take effect until async init is
+ // done.
+
+ MOZ_ALWAYS_SUCCEEDS(mTarget->Dispatch(NS_NewRunnableFunction(
+ __func__, [&] { mMirror.Connect(&mCanonical); })));
+ mCanonical = 1;
+ mirrorPromise = ReadMirrorAsync();
+ })));
+
+ // Make sure Mirror::Connect has run on mTarget.
+ mTarget->AwaitIdle();
+
+ // Make sure Canonical::AddMirror has run on this thread.
+ NS_ProcessPendingEvents(nullptr);
+
+ // Prior to establishing the connection, a value has not been mirrored.
+ EXPECT_EQ(WaitFor(mirrorPromise).unwrap(), 0);
+
+ // Once a connection has been establised, event ordering is as expected.
+ mCanonical = 2;
+ EXPECT_EQ(WaitFor(ReadMirrorAsync()).unwrap(), 2);
+
+ MOZ_ALWAYS_SUCCEEDS(mTarget->Dispatch(NS_NewRunnableFunction(
+ __func__, [&] { mMirror.DisconnectIfConnected(); })));
+ })));
+}
+
+TEST_F(StateMirroringTest, CanonicalInitiatedEventOrdering) {
+ // Note that this requires the tail dispatcher, which is not available until
+ // we are processing events.
+ ASSERT_FALSE(AbstractThread::GetCurrent()->IsTailDispatcherAvailable());
+
+ MOZ_ALWAYS_SUCCEEDS(NS_DispatchAndSpinEventLoopUntilComplete(
+ "NeedTailDispatcher"_ns, GetCurrentSerialEventTarget(),
+ NS_NewRunnableFunction(__func__, [&] {
+ ASSERT_TRUE(AbstractThread::GetCurrent()->IsTailDispatcherAvailable());
+
+ mCanonical.ConnectMirror(&mMirror);
+
+ // Event ordering is as expected immediately.
+ mCanonical = 1;
+ EXPECT_EQ(WaitFor(ReadMirrorAsync()).unwrap(), 1);
+
+ mCanonical.DisconnectAll();
+ })));
+}
+
+} // namespace TestStateMirroring