summaryrefslogtreecommitdiffstats
path: root/dom/media/gtest/TestPacer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/gtest/TestPacer.cpp')
-rw-r--r--dom/media/gtest/TestPacer.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/dom/media/gtest/TestPacer.cpp b/dom/media/gtest/TestPacer.cpp
new file mode 100644
index 0000000000..5d21ce1215
--- /dev/null
+++ b/dom/media/gtest/TestPacer.cpp
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "Pacer.h"
+#include "VideoUtils.h"
+#include "WaitFor.h"
+
+using namespace mozilla;
+
+template <typename T>
+class PacerTest {
+ protected:
+ explicit PacerTest(TimeDuration aDuplicationInterval)
+ : mTaskQueue(TaskQueue::Create(
+ GetMediaThreadPool(MediaThreadType::WEBRTC_WORKER), "PacerTest")),
+ mPacer(MakeRefPtr<Pacer<T>>(mTaskQueue, aDuplicationInterval)),
+ mInterval(aDuplicationInterval) {}
+
+ // Helper for calling `mPacer->Enqueue(...)`. Dispatches an event to the
+ // current thread which will enqueue the event to make sure that any listeners
+ // registered by a call to `WaitFor(...)` have been registered before events
+ // start being processed on a background queue.
+ void EnqueueSoon(T aItem, TimeStamp aTime) {
+ MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NS_NewRunnableFunction(
+ "PacerTest::EnqueueSoon",
+ [pacer = mPacer, aItem = std::move(aItem), aTime] {
+ pacer->Enqueue(std::move(aItem), aTime);
+ })));
+ }
+
+ void TearDown() {
+ mPacer->Shutdown()->Then(mTaskQueue, __func__,
+ [tq = mTaskQueue] { tq->BeginShutdown(); });
+ }
+
+ const RefPtr<TaskQueue> mTaskQueue;
+ const RefPtr<Pacer<T>> mPacer;
+ const TimeDuration mInterval;
+};
+
+class PacerTestInt : public PacerTest<int>, public ::testing::Test {
+ protected:
+ explicit PacerTestInt(TimeDuration aDuplicationInterval)
+ : PacerTest<int>(aDuplicationInterval) {}
+
+ void TearDown() override { PacerTest::TearDown(); }
+};
+
+class PacerTestIntLongDuplication : public PacerTestInt {
+ protected:
+ PacerTestIntLongDuplication() : PacerTestInt(TimeDuration::FromSeconds(10)) {}
+};
+
+class PacerTestIntTenMsDuplication : public PacerTestInt {
+ protected:
+ PacerTestIntTenMsDuplication()
+ : PacerTestInt(TimeDuration::FromMilliseconds(10)) {}
+};
+
+TEST_F(PacerTestIntLongDuplication, Single) {
+ auto now = TimeStamp::Now();
+ auto d1 = TimeDuration::FromMilliseconds(100);
+ EnqueueSoon(1, now + d1);
+
+ auto [i, time] = WaitFor(TakeN(mPacer->PacedItemEvent(), 1)).unwrap()[0];
+ EXPECT_GE(TimeStamp::Now() - now, d1);
+ EXPECT_EQ(i, 1);
+ EXPECT_EQ(time - now, d1);
+}
+
+TEST_F(PacerTestIntLongDuplication, Past) {
+ auto now = TimeStamp::Now();
+ auto d1 = TimeDuration::FromMilliseconds(100);
+ EnqueueSoon(1, now - d1);
+
+ auto [i, time] = WaitFor(TakeN(mPacer->PacedItemEvent(), 1)).unwrap()[0];
+ EXPECT_GE(TimeStamp::Now() - now, -d1);
+ EXPECT_EQ(i, 1);
+ EXPECT_EQ(time - now, -d1);
+}
+
+TEST_F(PacerTestIntLongDuplication, TimeReset) {
+ auto now = TimeStamp::Now();
+ auto d1 = TimeDuration::FromMilliseconds(100);
+ auto d2 = TimeDuration::FromMilliseconds(200);
+ auto d3 = TimeDuration::FromMilliseconds(300);
+ EnqueueSoon(1, now + d1);
+ EnqueueSoon(2, now + d3);
+ EnqueueSoon(3, now + d2);
+
+ auto items = WaitFor(TakeN(mPacer->PacedItemEvent(), 2)).unwrap();
+
+ {
+ auto [i, time] = items[0];
+ EXPECT_GE(TimeStamp::Now() - now, d1);
+ EXPECT_EQ(i, 1);
+ EXPECT_EQ(time - now, d1);
+ }
+ {
+ auto [i, time] = items[1];
+ EXPECT_GE(TimeStamp::Now() - now, d2);
+ EXPECT_EQ(i, 3);
+ EXPECT_EQ(time - now, d2);
+ }
+}
+
+TEST_F(PacerTestIntTenMsDuplication, SingleDuplication) {
+ auto now = TimeStamp::Now();
+ auto d1 = TimeDuration::FromMilliseconds(100);
+ EnqueueSoon(1, now + d1);
+
+ auto items = WaitFor(TakeN(mPacer->PacedItemEvent(), 2)).unwrap();
+
+ {
+ auto [i, time] = items[0];
+ EXPECT_GE(TimeStamp::Now() - now, d1);
+ EXPECT_EQ(i, 1);
+ EXPECT_EQ(time - now, d1);
+ }
+ {
+ auto [i, time] = items[1];
+ EXPECT_GE(TimeStamp::Now() - now, d1 + mInterval);
+ EXPECT_EQ(i, 1);
+ EXPECT_EQ(time - now, d1 + mInterval);
+ }
+}
+
+TEST_F(PacerTestIntTenMsDuplication, RacyDuplication1) {
+ auto now = TimeStamp::Now();
+ auto d1 = TimeDuration::FromMilliseconds(100);
+ auto d2 = d1 + mInterval - TimeDuration::FromMicroseconds(1);
+ EnqueueSoon(1, now + d1);
+ EnqueueSoon(2, now + d2);
+
+ auto items = WaitFor(TakeN(mPacer->PacedItemEvent(), 3)).unwrap();
+
+ {
+ auto [i, time] = items[0];
+ EXPECT_GE(TimeStamp::Now() - now, d1);
+ EXPECT_EQ(i, 1);
+ EXPECT_EQ(time - now, d1);
+ }
+ {
+ auto [i, time] = items[1];
+ EXPECT_GE(TimeStamp::Now() - now, d2);
+ EXPECT_EQ(i, 2);
+ EXPECT_EQ(time - now, d2);
+ }
+ {
+ auto [i, time] = items[2];
+ EXPECT_GE(TimeStamp::Now() - now, d2 + mInterval);
+ EXPECT_EQ(i, 2);
+ EXPECT_EQ(time - now, d2 + mInterval);
+ }
+}
+
+TEST_F(PacerTestIntTenMsDuplication, RacyDuplication2) {
+ auto now = TimeStamp::Now();
+ auto d1 = TimeDuration::FromMilliseconds(100);
+ auto d2 = d1 + mInterval + TimeDuration::FromMicroseconds(1);
+ EnqueueSoon(1, now + d1);
+ EnqueueSoon(2, now + d2);
+
+ auto items = WaitFor(TakeN(mPacer->PacedItemEvent(), 3)).unwrap();
+
+ {
+ auto [i, time] = items[0];
+ EXPECT_GE(TimeStamp::Now() - now, d1);
+ EXPECT_EQ(i, 1);
+ EXPECT_EQ(time - now, d1);
+ }
+ {
+ auto [i, time] = items[1];
+ EXPECT_GE(TimeStamp::Now() - now, d1 + mInterval);
+ EXPECT_EQ(i, 1);
+ EXPECT_EQ(time - now, d1 + mInterval);
+ }
+ {
+ auto [i, time] = items[2];
+ EXPECT_GE(TimeStamp::Now() - now, d2);
+ EXPECT_EQ(i, 2);
+ EXPECT_EQ(time - now, d2);
+ }
+}