| // Copyright 2017 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 "chrome/browser/resource_coordinator/lifecycle_unit_base.h" |
| |
| #include "base/macros.h" |
| #include "base/test/simple_test_tick_clock.h" |
| #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h" |
| #include "chrome/browser/resource_coordinator/lifecycle_unit_observer.h" |
| #include "chrome/browser/resource_coordinator/lifecycle_unit_source_base.h" |
| #include "chrome/browser/resource_coordinator/test_lifecycle_unit.h" |
| #include "chrome/browser/resource_coordinator/time.h" |
| #include "chrome/browser/resource_coordinator/usage_clock.h" |
| #include "content/public/browser/visibility.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace resource_coordinator { |
| |
| namespace { |
| |
| class MockLifecycleUnitObserver : public LifecycleUnitObserver { |
| public: |
| MockLifecycleUnitObserver() = default; |
| |
| MOCK_METHOD3(OnLifecycleUnitStateChanged, |
| void(LifecycleUnit*, |
| LifecycleUnitState, |
| LifecycleUnitStateChangeReason)); |
| MOCK_METHOD2(OnLifecycleUnitVisibilityChanged, |
| void(LifecycleUnit*, content::Visibility)); |
| MOCK_METHOD1(OnLifecycleUnitDestroyed, void(LifecycleUnit*)); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MockLifecycleUnitObserver); |
| }; |
| |
| class LifecycleUnitBaseTest : public testing::Test { |
| protected: |
| LifecycleUnitBaseTest() { |
| metrics::DesktopSessionDurationTracker::Initialize(); |
| usage_clock_ = std::make_unique<UsageClock>(); |
| } |
| |
| ~LifecycleUnitBaseTest() { |
| usage_clock_.reset(); |
| metrics::DesktopSessionDurationTracker::CleanupForTesting(); |
| } |
| |
| base::SimpleTestTickClock test_clock_; |
| ScopedSetTickClockForTesting scoped_set_tick_clock_for_testing_{&test_clock_}; |
| testing::StrictMock<MockLifecycleUnitObserver> observer_; |
| std::unique_ptr<UsageClock> usage_clock_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(LifecycleUnitBaseTest); |
| }; |
| |
| } // namespace |
| |
| // Verify that GetID() returns different ids for different LifecycleUnits, but |
| // always the same id for the same LifecycleUnit. |
| TEST_F(LifecycleUnitBaseTest, GetID) { |
| TestLifecycleUnit a; |
| TestLifecycleUnit b; |
| TestLifecycleUnit c; |
| |
| EXPECT_NE(a.GetID(), b.GetID()); |
| EXPECT_NE(a.GetID(), c.GetID()); |
| EXPECT_NE(b.GetID(), c.GetID()); |
| |
| EXPECT_EQ(a.GetID(), a.GetID()); |
| EXPECT_EQ(b.GetID(), b.GetID()); |
| EXPECT_EQ(c.GetID(), c.GetID()); |
| } |
| |
| // Verify that the state change time is updated when the state changes. |
| TEST_F(LifecycleUnitBaseTest, SetStateUpdatesTime) { |
| TestLifecycleUnit lifecycle_unit; |
| EXPECT_EQ(NowTicks(), lifecycle_unit.GetStateChangeTime()); |
| |
| test_clock_.Advance(base::TimeDelta::FromSeconds(1)); |
| base::TimeTicks first_state_change_time = NowTicks(); |
| lifecycle_unit.SetState(LifecycleUnitState::DISCARDED, |
| LifecycleUnitStateChangeReason::BROWSER_INITIATED); |
| EXPECT_EQ(first_state_change_time, lifecycle_unit.GetStateChangeTime()); |
| test_clock_.Advance(base::TimeDelta::FromSeconds(1)); |
| EXPECT_EQ(first_state_change_time, lifecycle_unit.GetStateChangeTime()); |
| } |
| |
| // Verify that observers are notified when the state changes and when the |
| // LifecycleUnit is destroyed. |
| TEST_F(LifecycleUnitBaseTest, SetStateNotifiesObservers) { |
| TestLifecycleUnit lifecycle_unit; |
| lifecycle_unit.AddObserver(&observer_); |
| |
| // Observer is notified when the state changes. |
| EXPECT_CALL(observer_, |
| OnLifecycleUnitStateChanged( |
| &lifecycle_unit, lifecycle_unit.GetState(), |
| LifecycleUnitStateChangeReason::BROWSER_INITIATED)); |
| lifecycle_unit.SetState(LifecycleUnitState::DISCARDED, |
| LifecycleUnitStateChangeReason::BROWSER_INITIATED); |
| testing::Mock::VerifyAndClear(&observer_); |
| |
| // Observer isn't notified when the state stays the same. |
| lifecycle_unit.SetState(LifecycleUnitState::DISCARDED, |
| LifecycleUnitStateChangeReason::BROWSER_INITIATED); |
| |
| lifecycle_unit.RemoveObserver(&observer_); |
| } |
| |
| // Verify that observers are notified when the LifecycleUnit is destroyed. |
| TEST_F(LifecycleUnitBaseTest, DestroyNotifiesObservers) { |
| { |
| TestLifecycleUnit lifecycle_unit; |
| lifecycle_unit.AddObserver(&observer_); |
| EXPECT_CALL(observer_, OnLifecycleUnitDestroyed(&lifecycle_unit)); |
| } |
| testing::Mock::VerifyAndClear(&observer_); |
| } |
| |
| // Verify the initial GetWallTimeWhenHidden()/GetChromeUsageTimeWhenHidden() of |
| // a visible LifecycleUnit. |
| TEST_F(LifecycleUnitBaseTest, InitialLastActiveTimeForVisibleLifecycleUnit) { |
| TestLifecycleUnit lifecycle_unit(content::Visibility::VISIBLE, |
| usage_clock_.get()); |
| EXPECT_EQ(base::TimeTicks::Max(), lifecycle_unit.GetWallTimeWhenHidden()); |
| EXPECT_EQ(base::TimeDelta::Max(), |
| lifecycle_unit.GetChromeUsageTimeWhenHidden()); |
| } |
| |
| // Verify the initial GetWallTimeWhenHidden()/GetChromeUsageTimeWhenHidden() of |
| // a hidden LifecycleUnit. |
| TEST_F(LifecycleUnitBaseTest, InitialLastActiveTimeForHiddenLifecycleUnit) { |
| TestLifecycleUnit lifecycle_unit(content::Visibility::HIDDEN, |
| usage_clock_.get()); |
| EXPECT_EQ(NowTicks(), lifecycle_unit.GetWallTimeWhenHidden()); |
| EXPECT_EQ(usage_clock_->GetTotalUsageTime(), |
| lifecycle_unit.GetChromeUsageTimeWhenHidden()); |
| } |
| |
| // Verify that observers are notified when the visibility of the LifecyleUnit |
| // changes. Verify that GetWallTimeWhenHidden()/GetChromeUsageTimeWhenHidden() |
| // are updated properly. |
| TEST_F(LifecycleUnitBaseTest, VisibilityChangeNotifiesObserversAndUpdatesTime) { |
| TestLifecycleUnit lifecycle_unit(content::Visibility::VISIBLE, |
| usage_clock_.get()); |
| lifecycle_unit.AddObserver(&observer_); |
| |
| // Observer is notified when the visibility changes. |
| test_clock_.Advance(base::TimeDelta::FromMinutes(1)); |
| base::TimeTicks wall_time_when_hidden = NowTicks(); |
| base::TimeDelta usage_time_when_hidden = usage_clock_->GetTotalUsageTime(); |
| EXPECT_CALL(observer_, OnLifecycleUnitVisibilityChanged( |
| &lifecycle_unit, content::Visibility::HIDDEN)) |
| .WillOnce(testing::Invoke( |
| [&](LifecycleUnit* lifecycle_unit, content::Visibility visibility) { |
| EXPECT_EQ(wall_time_when_hidden, |
| lifecycle_unit->GetWallTimeWhenHidden()); |
| EXPECT_EQ(usage_time_when_hidden, |
| lifecycle_unit->GetChromeUsageTimeWhenHidden()); |
| })); |
| lifecycle_unit.OnLifecycleUnitVisibilityChanged(content::Visibility::HIDDEN); |
| testing::Mock::VerifyAndClear(&observer_); |
| |
| test_clock_.Advance(base::TimeDelta::FromMinutes(1)); |
| EXPECT_CALL(observer_, OnLifecycleUnitVisibilityChanged( |
| &lifecycle_unit, content::Visibility::OCCLUDED)) |
| .WillOnce(testing::Invoke( |
| [&](LifecycleUnit* lifecycle_unit, content::Visibility visibility) { |
| EXPECT_EQ(wall_time_when_hidden, |
| lifecycle_unit->GetWallTimeWhenHidden()); |
| EXPECT_EQ(usage_time_when_hidden, |
| lifecycle_unit->GetChromeUsageTimeWhenHidden()); |
| })); |
| lifecycle_unit.OnLifecycleUnitVisibilityChanged( |
| content::Visibility::OCCLUDED); |
| testing::Mock::VerifyAndClear(&observer_); |
| |
| test_clock_.Advance(base::TimeDelta::FromMinutes(1)); |
| EXPECT_CALL(observer_, OnLifecycleUnitVisibilityChanged( |
| &lifecycle_unit, content::Visibility::VISIBLE)) |
| .WillOnce(testing::Invoke([&](LifecycleUnit* lifecycle_unit, |
| content::Visibility visibility) { |
| EXPECT_TRUE(lifecycle_unit->GetWallTimeWhenHidden().is_max()); |
| EXPECT_TRUE(lifecycle_unit->GetChromeUsageTimeWhenHidden().is_max()); |
| })); |
| lifecycle_unit.OnLifecycleUnitVisibilityChanged(content::Visibility::VISIBLE); |
| testing::Mock::VerifyAndClear(&observer_); |
| |
| lifecycle_unit.RemoveObserver(&observer_); |
| } |
| |
| namespace { |
| |
| class MockLifecycleUnitSource : public LifecycleUnitSourceBase { |
| public: |
| MockLifecycleUnitSource() = default; |
| virtual ~MockLifecycleUnitSource() = default; |
| |
| MOCK_METHOD0(OnFirstLifecycleUnitCreated, void()); |
| MOCK_METHOD0(OnAllLifecycleUnitsDestroyed, void()); |
| }; |
| |
| } // namespace |
| |
| TEST_F(LifecycleUnitBaseTest, SourceIsNotifiedOfUnitDeath) { |
| MockLifecycleUnitSource source; |
| EXPECT_EQ(0u, source.lifecycle_unit_count()); |
| |
| EXPECT_CALL(source, OnFirstLifecycleUnitCreated()); |
| std::unique_ptr<TestLifecycleUnit> unit1 = |
| std::make_unique<TestLifecycleUnit>(&source); |
| testing::Mock::VerifyAndClear(&source); |
| EXPECT_EQ(1u, source.lifecycle_unit_count()); |
| |
| std::unique_ptr<TestLifecycleUnit> unit2 = |
| std::make_unique<TestLifecycleUnit>(&source); |
| testing::Mock::VerifyAndClear(&source); |
| EXPECT_EQ(2u, source.lifecycle_unit_count()); |
| |
| unit1.reset(); |
| testing::Mock::VerifyAndClear(&source); |
| EXPECT_EQ(1u, source.lifecycle_unit_count()); |
| |
| EXPECT_CALL(source, OnAllLifecycleUnitsDestroyed()); |
| unit2.reset(); |
| testing::Mock::VerifyAndClear(&source); |
| EXPECT_EQ(0u, source.lifecycle_unit_count()); |
| } |
| |
| } // namespace resource_coordinator |