diff options
Diffstat (limited to 'xpcom/tests/gtest/TestStateMirroring.cpp')
-rw-r--r-- | xpcom/tests/gtest/TestStateMirroring.cpp | 121 |
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 |