OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "components/page_load_metrics/renderer/metrics_render_frame_observer.h" |
| 6 |
| 7 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/time/time.h" |
| 9 #include "base/timer/mock_timer.h" |
| 10 #include "components/page_load_metrics/common/page_load_metrics_messages.h" |
| 11 #include "components/page_load_metrics/common/page_load_timing.h" |
| 12 #include "ipc/ipc_message_macros.h" |
| 13 #include "testing/gmock/include/gmock/gmock.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" |
| 15 |
| 16 using testing::NiceMock; |
| 17 using testing::Return; |
| 18 using testing::StrictMock; |
| 19 |
| 20 namespace page_load_metrics { |
| 21 |
| 22 namespace { |
| 23 |
| 24 // IPC interceptor class, which we use to verify that certain IPC |
| 25 // messages get sent. |
| 26 class MockIPCInterceptor { |
| 27 public: |
| 28 void OnMessage(const IPC::Message& message) { |
| 29 IPC_BEGIN_MESSAGE_MAP(MockIPCInterceptor, message) |
| 30 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) |
| 31 IPC_MESSAGE_UNHANDLED(ADD_FAILURE()) |
| 32 IPC_END_MESSAGE_MAP() |
| 33 } |
| 34 |
| 35 MOCK_METHOD1(OnTimingUpdated, void(PageLoadTiming)); |
| 36 }; |
| 37 |
| 38 // Implementation of the MetricsRenderFrameObserver class we're testing, |
| 39 // with the GetTiming() and ShouldSendMetrics() methods stubbed out to make |
| 40 // the rest of the class more testable. |
| 41 class MockMetricsRenderFrameObserver : public MetricsRenderFrameObserver { |
| 42 public: |
| 43 MockMetricsRenderFrameObserver() : MetricsRenderFrameObserver(nullptr) { |
| 44 ON_CALL(*this, ShouldSendMetrics()).WillByDefault(Return(true)); |
| 45 } |
| 46 |
| 47 scoped_ptr<base::Timer> CreateTimer() const override { |
| 48 if (!mock_timer_) |
| 49 ADD_FAILURE() << "CreateTimer() called, but no MockTimer available."; |
| 50 return mock_timer_.Pass(); |
| 51 } |
| 52 |
| 53 // We intercept sent messages and dispatch them to a MockIPCInterceptor, which |
| 54 // we use to verify that the expected IPC messages get sent. |
| 55 virtual bool Send(IPC::Message* message) { |
| 56 interceptor_.OnMessage(*message); |
| 57 delete message; |
| 58 return true; |
| 59 } |
| 60 |
| 61 void set_mock_timer(scoped_ptr<base::Timer> timer) { |
| 62 ASSERT_EQ(nullptr, mock_timer_); |
| 63 mock_timer_ = timer.Pass(); |
| 64 } |
| 65 |
| 66 MOCK_CONST_METHOD0(GetTiming, PageLoadTiming()); |
| 67 MOCK_CONST_METHOD0(ShouldSendMetrics, bool()); |
| 68 MockIPCInterceptor* ipc_interceptor() { return &interceptor_; } |
| 69 |
| 70 private: |
| 71 StrictMock<MockIPCInterceptor> interceptor_; |
| 72 mutable scoped_ptr<base::Timer> mock_timer_; |
| 73 }; |
| 74 |
| 75 typedef testing::Test MetricsRenderFrameObserverTest; |
| 76 |
| 77 TEST_F(MetricsRenderFrameObserverTest, NoMetrics) { |
| 78 NiceMock<MockMetricsRenderFrameObserver> observer; |
| 79 base::MockTimer* mock_timer = new base::MockTimer(false, false); |
| 80 observer.set_mock_timer(make_scoped_ptr(mock_timer)); |
| 81 observer.DidCommitProvisionalLoad(true, false); |
| 82 |
| 83 EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(PageLoadTiming())); |
| 84 observer.DidChangePerformanceTiming(); |
| 85 ASSERT_FALSE(mock_timer->IsRunning()); |
| 86 } |
| 87 |
| 88 TEST_F(MetricsRenderFrameObserverTest, SingleMetric) { |
| 89 base::Time nav_start = base::Time::FromDoubleT(10); |
| 90 base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(10); |
| 91 |
| 92 NiceMock<MockMetricsRenderFrameObserver> observer; |
| 93 base::MockTimer* mock_timer = new base::MockTimer(false, false); |
| 94 observer.set_mock_timer(make_scoped_ptr(mock_timer)); |
| 95 observer.DidCommitProvisionalLoad(true, false); |
| 96 |
| 97 PageLoadTiming timing; |
| 98 timing.navigation_start = nav_start; |
| 99 timing.first_layout = first_layout; |
| 100 EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing)); |
| 101 |
| 102 EXPECT_CALL(*observer.ipc_interceptor(), OnTimingUpdated(timing)); |
| 103 |
| 104 observer.DidChangePerformanceTiming(); |
| 105 mock_timer->Fire(); |
| 106 } |
| 107 |
| 108 TEST_F(MetricsRenderFrameObserverTest, MultipleMetrics) { |
| 109 base::Time nav_start = base::Time::FromDoubleT(10); |
| 110 base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2); |
| 111 base::TimeDelta dom_event = base::TimeDelta::FromMillisecondsD(2); |
| 112 base::TimeDelta load_event = base::TimeDelta::FromMillisecondsD(2); |
| 113 |
| 114 NiceMock<MockMetricsRenderFrameObserver> observer; |
| 115 base::MockTimer* mock_timer = new base::MockTimer(false, false); |
| 116 observer.set_mock_timer(make_scoped_ptr(mock_timer)); |
| 117 observer.DidCommitProvisionalLoad(true, false); |
| 118 |
| 119 PageLoadTiming timing; |
| 120 timing.navigation_start = nav_start; |
| 121 timing.first_layout = first_layout; |
| 122 timing.dom_content_loaded_event_start = dom_event; |
| 123 EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing)); |
| 124 |
| 125 EXPECT_CALL(*observer.ipc_interceptor(), OnTimingUpdated(timing)); |
| 126 observer.DidChangePerformanceTiming(); |
| 127 mock_timer->Fire(); |
| 128 |
| 129 // At this point, we should have triggered the generation of two metrics. |
| 130 // Verify and reset the observer's expectations before moving on to the next |
| 131 // part of the test. |
| 132 testing::Mock::VerifyAndClearExpectations(observer.ipc_interceptor()); |
| 133 |
| 134 timing.load_event_start = load_event; |
| 135 EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing)); |
| 136 |
| 137 EXPECT_CALL(*observer.ipc_interceptor(), OnTimingUpdated(timing)); |
| 138 observer.DidChangePerformanceTiming(); |
| 139 mock_timer->Fire(); |
| 140 |
| 141 // Verify and reset the observer's expectations before moving on to the next |
| 142 // part of the test. |
| 143 testing::Mock::VerifyAndClearExpectations(observer.ipc_interceptor()); |
| 144 |
| 145 // The PageLoadTiming above includes timing information for the first layout, |
| 146 // dom content, and load metrics. However, since we've already generated |
| 147 // timing information for all of these metrics previously, we do not expect |
| 148 // this invocation to generate any additional metrics. |
| 149 observer.DidChangePerformanceTiming(); |
| 150 ASSERT_FALSE(mock_timer->IsRunning()); |
| 151 } |
| 152 |
| 153 TEST_F(MetricsRenderFrameObserverTest, MultipleNavigations) { |
| 154 base::Time nav_start = base::Time::FromDoubleT(10); |
| 155 base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2); |
| 156 base::TimeDelta dom_event = base::TimeDelta::FromMillisecondsD(2); |
| 157 base::TimeDelta load_event = base::TimeDelta::FromMillisecondsD(2); |
| 158 |
| 159 NiceMock<MockMetricsRenderFrameObserver> observer; |
| 160 base::MockTimer* mock_timer = new base::MockTimer(false, false); |
| 161 observer.set_mock_timer(make_scoped_ptr(mock_timer)); |
| 162 observer.DidCommitProvisionalLoad(true, false); |
| 163 |
| 164 PageLoadTiming timing; |
| 165 timing.navigation_start = nav_start; |
| 166 timing.first_layout = first_layout; |
| 167 timing.dom_content_loaded_event_start = dom_event; |
| 168 timing.load_event_start = load_event; |
| 169 EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing)); |
| 170 EXPECT_CALL(*observer.ipc_interceptor(), OnTimingUpdated(timing)); |
| 171 observer.DidChangePerformanceTiming(); |
| 172 mock_timer->Fire(); |
| 173 |
| 174 // At this point, we should have triggered the generation of two metrics. |
| 175 // Verify and reset the observer's expectations before moving on to the next |
| 176 // part of the test. |
| 177 testing::Mock::VerifyAndClearExpectations(observer.ipc_interceptor()); |
| 178 |
| 179 base::Time nav_start_2 = base::Time::FromDoubleT(100); |
| 180 base::TimeDelta first_layout_2 = base::TimeDelta::FromMillisecondsD(20); |
| 181 base::TimeDelta dom_event_2 = base::TimeDelta::FromMillisecondsD(20); |
| 182 base::TimeDelta load_event_2 = base::TimeDelta::FromMillisecondsD(20); |
| 183 PageLoadTiming timing_2; |
| 184 timing_2.navigation_start = nav_start_2; |
| 185 timing_2.first_layout = first_layout_2; |
| 186 timing_2.dom_content_loaded_event_start = dom_event_2; |
| 187 timing_2.load_event_start = load_event_2; |
| 188 |
| 189 base::MockTimer* mock_timer2 = new base::MockTimer(false, false); |
| 190 observer.set_mock_timer(make_scoped_ptr(mock_timer2)); |
| 191 observer.DidCommitProvisionalLoad(true, false); |
| 192 EXPECT_CALL(*observer.ipc_interceptor(), OnTimingUpdated(timing)); |
| 193 observer.DidChangePerformanceTiming(); |
| 194 mock_timer2->Fire(); |
| 195 } |
| 196 |
| 197 } // namespace |
| 198 |
| 199 } // namespace page_load_metrics |
OLD | NEW |