Index: components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc |
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a424b9b3a892b46366d1326a9a4ff66103a84d75 |
--- /dev/null |
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc |
@@ -0,0 +1,148 @@ |
+// Copyright 2015 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 "components/page_load_metrics/renderer/page_timing_metrics_sender.h" |
+ |
+#include "base/time/time.h" |
+#include "base/timer/mock_timer.h" |
+#include "components/page_load_metrics/common/page_load_metrics_messages.h" |
+#include "components/page_load_metrics/common/page_load_timing.h" |
+#include "ipc/ipc_message.h" |
+#include "ipc/ipc_message_macros.h" |
+#include "ipc/ipc_sender.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace page_load_metrics { |
+ |
+class MockIPCSender : public IPC::Sender { |
+ public: |
+ bool Send(IPC::Message* message) { |
+ IPC_BEGIN_MESSAGE_MAP(MockIPCSender, *message) |
+ IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) |
+ IPC_MESSAGE_UNHANDLED(ADD_FAILURE()) |
+ IPC_END_MESSAGE_MAP() |
+ |
+ delete message; |
+ return true; |
+ } |
+ |
+ MOCK_METHOD1(OnTimingUpdated, void(PageLoadTiming)); |
+}; |
+ |
+// Thin wrapper around PageTimingMetricsSender that provides access to the |
+// MockTimer instance. |
+class TestPageTimingMetricsSender : public PageTimingMetricsSender { |
+ public: |
+ explicit TestPageTimingMetricsSender(IPC::Sender* ipc_sender) |
+ : PageTimingMetricsSender( |
+ ipc_sender, |
+ MSG_ROUTING_NONE, |
+ scoped_ptr<base::Timer>(new base::MockTimer(false, false))) {} |
+ |
+ base::MockTimer* mock_timer() const { |
+ return reinterpret_cast<base::MockTimer*>(timer()); |
+ } |
+}; |
+ |
+class PageTimingMetricsSenderTest : public testing::Test { |
+ public: |
+ PageTimingMetricsSenderTest() : metrics_sender_(&mock_ipc_sender_) {} |
+ |
+ protected: |
+ testing::StrictMock<MockIPCSender> mock_ipc_sender_; |
+ TestPageTimingMetricsSender metrics_sender_; |
+}; |
+ |
+TEST_F(PageTimingMetricsSenderTest, Basic) { |
+ base::Time nav_start = base::Time::FromDoubleT(10); |
+ base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2); |
+ |
+ PageLoadTiming timing; |
+ timing.navigation_start = nav_start; |
+ timing.first_layout = first_layout; |
+ |
+ metrics_sender_.Send(timing); |
+ |
+ // Firing the timer should trigger sending of an OnTimingUpdated IPC. |
+ EXPECT_CALL(mock_ipc_sender_, OnTimingUpdated(timing)); |
+ ASSERT_TRUE(metrics_sender_.mock_timer()->IsRunning()); |
+ metrics_sender_.mock_timer()->Fire(); |
+ EXPECT_FALSE(metrics_sender_.mock_timer()->IsRunning()); |
+ |
+ // At this point, we should have triggered the send of the PageLoadTiming IPC. |
+ testing::Mock::VerifyAndClearExpectations(&mock_ipc_sender_); |
+ |
+ // Attempt to send the same timing instance again. The send should be |
+ // suppressed, since the timing instance hasn't changed since the last send. |
+ metrics_sender_.Send(timing); |
+ EXPECT_FALSE(metrics_sender_.mock_timer()->IsRunning()); |
+} |
+ |
+TEST_F(PageTimingMetricsSenderTest, CoalesceMultipleIPCs) { |
+ base::Time nav_start = base::Time::FromDoubleT(10); |
+ base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2); |
+ base::TimeDelta load_event = base::TimeDelta::FromMillisecondsD(4); |
+ |
+ PageLoadTiming timing; |
+ timing.navigation_start = nav_start; |
+ timing.first_layout = first_layout; |
+ |
+ metrics_sender_.Send(timing); |
+ ASSERT_TRUE(metrics_sender_.mock_timer()->IsRunning()); |
+ |
+ // Send an updated PageLoadTiming before the timer has fired. When the timer |
+ // fires, the updated PageLoadTiming should be sent. |
+ timing.load_event_start = load_event; |
+ metrics_sender_.Send(timing); |
+ |
+ // Firing the timer should trigger sending of the OnTimingUpdated IPC with |
+ // the most recently provided PageLoadTiming instance. |
+ EXPECT_CALL(mock_ipc_sender_, OnTimingUpdated(timing)); |
+ metrics_sender_.mock_timer()->Fire(); |
+ EXPECT_FALSE(metrics_sender_.mock_timer()->IsRunning()); |
+} |
+ |
+TEST_F(PageTimingMetricsSenderTest, MultipleIPCs) { |
+ base::Time nav_start = base::Time::FromDoubleT(10); |
+ base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2); |
+ base::TimeDelta load_event = base::TimeDelta::FromMillisecondsD(4); |
+ |
+ PageLoadTiming timing; |
+ timing.navigation_start = nav_start; |
+ timing.first_layout = first_layout; |
+ |
+ metrics_sender_.Send(timing); |
+ ASSERT_TRUE(metrics_sender_.mock_timer()->IsRunning()); |
+ EXPECT_CALL(mock_ipc_sender_, OnTimingUpdated(timing)); |
+ metrics_sender_.mock_timer()->Fire(); |
+ EXPECT_FALSE(metrics_sender_.mock_timer()->IsRunning()); |
+ testing::Mock::VerifyAndClearExpectations(&mock_ipc_sender_); |
+ |
+ // Send an updated PageLoadTiming after the timer for the first send request |
+ // has fired, and verify that a second IPC is sent. |
+ timing.load_event_start = load_event; |
+ metrics_sender_.Send(timing); |
+ ASSERT_TRUE(metrics_sender_.mock_timer()->IsRunning()); |
+ EXPECT_CALL(mock_ipc_sender_, OnTimingUpdated(timing)); |
+ metrics_sender_.mock_timer()->Fire(); |
+ EXPECT_FALSE(metrics_sender_.mock_timer()->IsRunning()); |
+} |
+ |
+TEST_F(PageTimingMetricsSenderTest, SendIPCOnDestructor) { |
+ PageLoadTiming timing; |
+ timing.navigation_start = base::Time::FromDoubleT(10); |
+ { |
+ // This test wants to verify behavior in the PageTimingMetricsSender |
+ // destructor, so we create our own instance to make it go out of scope |
+ // before the end of the test body. |
+ TestPageTimingMetricsSender sender(&mock_ipc_sender_); |
+ |
+ sender.Send(timing); |
+ EXPECT_CALL(mock_ipc_sender_, OnTimingUpdated(timing)); |
+ ASSERT_TRUE(sender.mock_timer()->IsRunning()); |
+ } |
+} |
+ |
+} // namespace page_load_metrics |