|  | // Copyright 2019 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/chromeos/throttle_service.h" | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "chrome/test/base/testing_profile.h" | 
|  | #include "content/public/test/browser_task_environment.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace chromeos { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class TestObserver : public ThrottleService::ServiceObserver { | 
|  | public: | 
|  | TestObserver() = default; | 
|  | ~TestObserver() override = default; | 
|  |  | 
|  | // ThrottleService::Observer: | 
|  | void OnThrottle(ThrottleObserver::PriorityLevel level) override { | 
|  | last_level_ = level; | 
|  | ++update_count_; | 
|  | } | 
|  |  | 
|  | int GetUpdateCountAndReset() { | 
|  | const int update_count = update_count_; | 
|  | update_count_ = 0; | 
|  | return update_count; | 
|  | } | 
|  |  | 
|  | ThrottleObserver::PriorityLevel last_level() const { return last_level_; } | 
|  |  | 
|  | private: | 
|  | int update_count_ = 0; | 
|  | ThrottleObserver::PriorityLevel last_level_ = | 
|  | ThrottleObserver::PriorityLevel::UNKNOWN; | 
|  |  | 
|  | TestObserver(TestObserver const&) = delete; | 
|  | TestObserver& operator=(TestObserver const&) = delete; | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class TestThrottleService : public ThrottleService { | 
|  | public: | 
|  | using ThrottleService::ThrottleService; | 
|  |  | 
|  | size_t throttle_instance_count() const { return throttle_instance_count_; } | 
|  |  | 
|  | size_t uma_count() { return record_uma_counter_; } | 
|  |  | 
|  | ThrottleObserver::PriorityLevel last_throttle_level() const { | 
|  | return last_throttle_level_; | 
|  | } | 
|  |  | 
|  | const std::string& last_recorded_observer_name() { | 
|  | return last_recorded_observer_name_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void ThrottleInstance(ThrottleObserver::PriorityLevel level) override { | 
|  | ++throttle_instance_count_; | 
|  | last_throttle_level_ = level; | 
|  | } | 
|  |  | 
|  | void RecordCpuRestrictionDisabledUMA(const std::string& observer_name, | 
|  | base::TimeDelta delta) override { | 
|  | ++record_uma_counter_; | 
|  | last_recorded_observer_name_ = observer_name; | 
|  | } | 
|  |  | 
|  | size_t throttle_instance_count_{0}; | 
|  | size_t record_uma_counter_{0}; | 
|  | std::string last_recorded_observer_name_; | 
|  | ThrottleObserver::PriorityLevel last_throttle_level_{ | 
|  | ThrottleObserver::PriorityLevel::UNKNOWN}; | 
|  | }; | 
|  |  | 
|  | class ThrottleServiceTest : public testing::Test { | 
|  | public: | 
|  | ThrottleServiceTest() : service_(&profile_) { | 
|  | std::vector<std::unique_ptr<ThrottleObserver>> observers; | 
|  | observers.push_back(std::make_unique<TestCriticalObserver>(this)); | 
|  | observers.push_back(std::make_unique<TestLowObserver>(this)); | 
|  | service_.SetObserversForTesting(std::move(observers)); | 
|  | } | 
|  |  | 
|  | void set_critical_observer(ThrottleObserver* observer) { | 
|  | critical_observer_ = observer; | 
|  | } | 
|  |  | 
|  | void set_low_observer(ThrottleObserver* observer) { | 
|  | low_observer_ = observer; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | TestThrottleService* service() { return &service_; } | 
|  |  | 
|  | ThrottleObserver* critical_observer() { return critical_observer_; } | 
|  |  | 
|  | ThrottleObserver* low_observer() { return low_observer_; } | 
|  |  | 
|  | private: | 
|  | class TestCriticalObserver : public ThrottleObserver { | 
|  | public: | 
|  | explicit TestCriticalObserver(ThrottleServiceTest* test) | 
|  | : ThrottleObserver(ThrottleObserver::PriorityLevel::CRITICAL, | 
|  | "CriticalObserver"), | 
|  | test_(test) { | 
|  | test_->set_critical_observer(this); | 
|  | } | 
|  | ~TestCriticalObserver() override { test_->set_critical_observer(nullptr); } | 
|  |  | 
|  | private: | 
|  | ThrottleServiceTest* test_; | 
|  | }; | 
|  | class TestLowObserver : public ThrottleObserver { | 
|  | public: | 
|  | explicit TestLowObserver(ThrottleServiceTest* test) | 
|  | : ThrottleObserver(ThrottleObserver::PriorityLevel::LOW, "LowObserver"), | 
|  | test_(test) { | 
|  | test_->set_low_observer(this); | 
|  | } | 
|  | ~TestLowObserver() override { test_->set_low_observer(nullptr); } | 
|  |  | 
|  | private: | 
|  | ThrottleServiceTest* test_; | 
|  | }; | 
|  |  | 
|  | content::BrowserTaskEnvironment task_environment_; | 
|  | TestingProfile profile_; | 
|  | TestThrottleService service_; | 
|  | ThrottleObserver* critical_observer_{nullptr}; | 
|  | ThrottleObserver* low_observer_{nullptr}; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ThrottleServiceTest); | 
|  | }; | 
|  |  | 
|  | TEST_F(ThrottleServiceTest, TestConstructDestruct) {} | 
|  |  | 
|  | // Tests that the ThrottleService calls ThrottleInstance with the correct level | 
|  | // when there is a change in observers, but skips the call if new level is same | 
|  | // as before. | 
|  | TEST_F(ThrottleServiceTest, TestOnObserverStateChanged) { | 
|  | EXPECT_EQ(0U, service()->throttle_instance_count()); | 
|  |  | 
|  | service()->NotifyObserverStateChangedForTesting(); | 
|  | EXPECT_EQ(1U, service()->throttle_instance_count()); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, | 
|  | service()->last_throttle_level()); | 
|  |  | 
|  | // ThrottleService level is already LOW, expect no change. | 
|  | low_observer()->SetActive(true); | 
|  | EXPECT_EQ(1U, service()->throttle_instance_count()); | 
|  |  | 
|  | critical_observer()->SetActive(true); | 
|  | EXPECT_EQ(2U, service()->throttle_instance_count()); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL, | 
|  | service()->last_throttle_level()); | 
|  |  | 
|  | critical_observer()->SetActive(false); | 
|  | EXPECT_EQ(3U, service()->throttle_instance_count()); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, | 
|  | service()->last_throttle_level()); | 
|  | } | 
|  |  | 
|  | // Tests that ArcInstanceThrottle records the duration that the effective | 
|  | // observer is active. | 
|  | TEST_F(ThrottleServiceTest, RecordCpuRestrictionDisabledUMA) { | 
|  | EXPECT_EQ(0U, service()->uma_count()); | 
|  |  | 
|  | // The effective observer transitions from null to critical_observer; no UMA | 
|  | // is recorded yet. | 
|  | critical_observer()->SetActive(true); | 
|  | EXPECT_EQ(0U, service()->uma_count()); | 
|  | low_observer()->SetActive(true); | 
|  | EXPECT_EQ(0U, service()->uma_count()); | 
|  |  | 
|  | // The effective observer transitions from critical_observer to low_observer; | 
|  | // UMA should be recorded for critical_observer. | 
|  | critical_observer()->SetActive(false); | 
|  | EXPECT_EQ(1U, service()->uma_count()); | 
|  | EXPECT_EQ(critical_observer()->name(), | 
|  | service()->last_recorded_observer_name()); | 
|  |  | 
|  | // Effective observer transitions from low_observer to critical_observer; UMA | 
|  | // should be recorded for low_observer. | 
|  | critical_observer()->SetActive(true); | 
|  | EXPECT_EQ(2U, service()->uma_count()); | 
|  | EXPECT_EQ(low_observer()->name(), service()->last_recorded_observer_name()); | 
|  |  | 
|  | // Effective observer transitions from critical_observer to null; UMA should | 
|  | // be recorded for critical_observer. | 
|  | low_observer()->SetActive(false); | 
|  | critical_observer()->SetActive(false); | 
|  | EXPECT_EQ(3U, service()->uma_count()); | 
|  | EXPECT_EQ(critical_observer()->name(), | 
|  | service()->last_recorded_observer_name()); | 
|  | } | 
|  |  | 
|  | // Tests that verifies enforcement mode. | 
|  | TEST_F(ThrottleServiceTest, TestEnforced) { | 
|  | low_observer()->SetActive(true); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level()); | 
|  | service()->SetEnforced(ThrottleObserver::PriorityLevel::NORMAL); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::NORMAL, service()->level()); | 
|  | service()->SetEnforced(ThrottleObserver::PriorityLevel::UNKNOWN); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level()); | 
|  |  | 
|  | low_observer()->SetActive(false); | 
|  | critical_observer()->SetActive(true); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL, | 
|  | service()->last_throttle_level()); | 
|  | service()->SetEnforced(ThrottleObserver::PriorityLevel::LOW); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level()); | 
|  | service()->SetEnforced(ThrottleObserver::PriorityLevel::UNKNOWN); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL, service()->level()); | 
|  | } | 
|  |  | 
|  | // Tests that verifies observer notifications. | 
|  | TEST_F(ThrottleServiceTest, TestObservers) { | 
|  | TestObserver test_observer; | 
|  | service()->AddServiceObserver(&test_observer); | 
|  | EXPECT_EQ(0, test_observer.GetUpdateCountAndReset()); | 
|  | low_observer()->SetActive(true); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, test_observer.last_level()); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level()); | 
|  | EXPECT_EQ(1, test_observer.GetUpdateCountAndReset()); | 
|  | low_observer()->SetActive(false); | 
|  | critical_observer()->SetActive(true); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL, | 
|  | test_observer.last_level()); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL, service()->level()); | 
|  | EXPECT_EQ(1, test_observer.GetUpdateCountAndReset()); | 
|  | service()->RemoveServiceObserver(&test_observer); | 
|  | critical_observer()->SetActive(false); | 
|  | low_observer()->SetActive(true); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL, | 
|  | test_observer.last_level()); | 
|  | EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level()); | 
|  | EXPECT_EQ(0, test_observer.GetUpdateCountAndReset()); | 
|  | } | 
|  |  | 
|  | }  // namespace chromeos |