blob: a8c75b3b9520ebe6d52072bb7cb0c6173cd0e39a [file] [log] [blame]
// 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