|  | // Copyright 2019 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "chrome/browser/ash/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 ash { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | constexpr const char kFirstObserverName[] = "o1"; | 
|  | constexpr const char kSecondObserverName[] = "o2"; | 
|  |  | 
|  | class TestObserver : public ThrottleService::ServiceObserver { | 
|  | public: | 
|  | TestObserver() = default; | 
|  | ~TestObserver() override = default; | 
|  |  | 
|  | // ThrottleService::Observer: | 
|  | void OnThrottle(bool was_throttled) override { | 
|  | last_was_throttled_ = was_throttled; | 
|  | ++update_count_; | 
|  | } | 
|  |  | 
|  | int GetUpdateCountAndReset() { | 
|  | const int update_count = update_count_; | 
|  | update_count_ = 0; | 
|  | return update_count; | 
|  | } | 
|  |  | 
|  | bool last_was_throttled() const { return last_was_throttled_; } | 
|  |  | 
|  | private: | 
|  | int update_count_ = 0; | 
|  | bool last_was_throttled_ = false; | 
|  |  | 
|  | 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_; } | 
|  |  | 
|  | bool last_should_throttle() const { return last_should_throttle_; } | 
|  |  | 
|  | const std::string& last_recorded_observer_name() { | 
|  | return last_recorded_observer_name_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void ThrottleInstance(bool should_throttle) override { | 
|  | ++throttle_instance_count_; | 
|  | last_should_throttle_ = should_throttle; | 
|  | } | 
|  |  | 
|  | 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_; | 
|  | bool last_should_throttle_ = false; | 
|  | }; | 
|  |  | 
|  | class ThrottleServiceTest : public testing::Test { | 
|  | public: | 
|  | ThrottleServiceTest() : service_(&profile_) { | 
|  | std::vector<std::unique_ptr<ThrottleObserver>> observers; | 
|  | observers.push_back(std::make_unique<ThrottleObserver>(kFirstObserverName)); | 
|  | observers.push_back( | 
|  | std::make_unique<ThrottleObserver>(kSecondObserverName)); | 
|  | service_.SetObserversForTesting(std::move(observers)); | 
|  | } | 
|  |  | 
|  | ThrottleServiceTest(const ThrottleServiceTest&) = delete; | 
|  | ThrottleServiceTest& operator=(const ThrottleServiceTest&) = delete; | 
|  |  | 
|  | protected: | 
|  | TestThrottleService* service() { return &service_; } | 
|  |  | 
|  | private: | 
|  | content::BrowserTaskEnvironment task_environment_; | 
|  | TestingProfile profile_; | 
|  | TestThrottleService service_; | 
|  | }; | 
|  |  | 
|  | TEST_F(ThrottleServiceTest, TestConstructDestruct) {} | 
|  |  | 
|  | // Tests that the ThrottleService calls ThrottleInstance with the correct | 
|  | // throttling when there is a change in observers, but skips the call if new | 
|  | // throttling is same as before. | 
|  | TEST_F(ThrottleServiceTest, TestOnObserverStateChanged) { | 
|  | EXPECT_EQ(0U, service()->throttle_instance_count()); | 
|  |  | 
|  | // Initially, it is throttled. | 
|  | service()->NotifyObserverStateChangedForTesting(); | 
|  | EXPECT_EQ(1U, service()->throttle_instance_count()); | 
|  | EXPECT_TRUE(service()->last_should_throttle()); | 
|  |  | 
|  | // Activate one of two observers. Verify it is unthrottled. | 
|  | service()->observers_for_testing()[0]->SetActive(true); | 
|  | EXPECT_EQ(2U, service()->throttle_instance_count()); | 
|  | EXPECT_FALSE(service()->last_should_throttle()); | 
|  |  | 
|  | // Activate the other observer too. Verify ThrottleInstance() is not called. | 
|  | service()->observers_for_testing()[1]->SetActive(true); | 
|  | EXPECT_EQ(2U, service()->throttle_instance_count()); | 
|  | EXPECT_FALSE(service()->last_should_throttle()); | 
|  |  | 
|  | // Deactivate one observer. Verify ThrottleInstance() is not called. | 
|  | service()->observers_for_testing()[1]->SetActive(false); | 
|  | EXPECT_EQ(2U, service()->throttle_instance_count()); | 
|  | EXPECT_FALSE(service()->last_should_throttle()); | 
|  |  | 
|  | // Deactivate the other observer too. Verify ThrottleInstance() is called. | 
|  | service()->observers_for_testing()[0]->SetActive(false); | 
|  | EXPECT_EQ(3U, service()->throttle_instance_count()); | 
|  | EXPECT_TRUE(service()->last_should_throttle()); | 
|  | } | 
|  |  | 
|  | // 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 the first one; no UMA | 
|  | // is recorded yet. | 
|  | service()->observers_for_testing()[0]->SetActive(true); | 
|  | EXPECT_EQ(0U, service()->uma_count()); | 
|  |  | 
|  | // The effective observer is still the first one. | 
|  | service()->observers_for_testing()[1]->SetActive(true); | 
|  | EXPECT_EQ(0U, service()->uma_count()); | 
|  |  | 
|  | // The effective observer transitions from the first one to the second one. | 
|  | // UMA should be recorded for the first one. | 
|  | service()->observers_for_testing()[0]->SetActive(false); | 
|  | EXPECT_EQ(1U, service()->uma_count()); | 
|  | EXPECT_EQ(service()->observers_for_testing()[0]->name(), | 
|  | service()->last_recorded_observer_name()); | 
|  |  | 
|  | // Effective observer transitions from the second one to the first one. UMA | 
|  | // should be recorded for the second one. | 
|  | service()->observers_for_testing()[0]->SetActive(true); | 
|  | EXPECT_EQ(2U, service()->uma_count()); | 
|  | EXPECT_EQ(service()->observers_for_testing()[1]->name(), | 
|  | service()->last_recorded_observer_name()); | 
|  |  | 
|  | // Effective observer transitions from the first one to null; UMA should | 
|  | // be recorded for critical_observer. | 
|  | service()->observers_for_testing()[1]->SetActive(false); | 
|  | service()->observers_for_testing()[0]->SetActive(false); | 
|  | EXPECT_EQ(3U, service()->uma_count()); | 
|  | EXPECT_EQ(service()->observers_for_testing()[0]->name(), | 
|  | service()->last_recorded_observer_name()); | 
|  | } | 
|  |  | 
|  | // Tests that verifies enforcement mode. | 
|  | TEST_F(ThrottleServiceTest, TestEnforced) { | 
|  | service()->observers_for_testing()[0]->SetActive(false); | 
|  | service()->observers_for_testing()[1]->SetActive(true); | 
|  | EXPECT_FALSE(service()->should_throttle()); | 
|  |  | 
|  | // Enforce the first observer which is not active. Verify the service is | 
|  | // throttled. | 
|  | service()->observers_for_testing()[0]->SetEnforced(true); | 
|  | EXPECT_TRUE(service()->should_throttle()); | 
|  |  | 
|  | // Stop enforcing it and verify the service is the service is unthrottled. | 
|  | service()->observers_for_testing()[0]->SetEnforced(false); | 
|  | EXPECT_FALSE(service()->should_throttle()); | 
|  | } | 
|  |  | 
|  | // Tests that verifies observer notifications. | 
|  | TEST_F(ThrottleServiceTest, TestObservers) { | 
|  | TestObserver test_observer; | 
|  | service()->AddServiceObserver(&test_observer); | 
|  |  | 
|  | // Activate the second observer. Verify that OnThrottle() is called. | 
|  | EXPECT_EQ(0, test_observer.GetUpdateCountAndReset()); | 
|  | service()->observers_for_testing()[1]->SetActive(true); | 
|  | EXPECT_FALSE(service()->should_throttle()); | 
|  | EXPECT_FALSE(test_observer.last_was_throttled()); | 
|  | EXPECT_EQ(1, test_observer.GetUpdateCountAndReset()); | 
|  |  | 
|  | // Activate the first observer too. Verify that OnThrottle() is NOT called | 
|  | // because the throttling is not changed. | 
|  | service()->observers_for_testing()[0]->SetActive(true); | 
|  | EXPECT_FALSE(service()->should_throttle()); | 
|  | EXPECT_FALSE(test_observer.last_was_throttled()); | 
|  | EXPECT_EQ(0, test_observer.GetUpdateCountAndReset()); | 
|  |  | 
|  | // Deactivate both. Verify that OnThrottle() is called. | 
|  | service()->observers_for_testing()[0]->SetActive(false); | 
|  | EXPECT_EQ(0, test_observer.GetUpdateCountAndReset());  // not yet called | 
|  | service()->observers_for_testing()[1]->SetActive(false); | 
|  | EXPECT_TRUE(service()->should_throttle()); | 
|  | EXPECT_TRUE(test_observer.last_was_throttled()); | 
|  | EXPECT_EQ(1, test_observer.GetUpdateCountAndReset()); | 
|  |  | 
|  | // Remove the observer. Verify that OnThrottle() is no longer called. | 
|  | service()->RemoveServiceObserver(&test_observer); | 
|  | service()->observers_for_testing()[1]->SetActive(true); | 
|  | EXPECT_FALSE(service()->should_throttle()); | 
|  | EXPECT_EQ(0, test_observer.GetUpdateCountAndReset()); | 
|  | } | 
|  |  | 
|  | // Tests that getting an observer by its name works. | 
|  | TEST_F(ThrottleServiceTest, TestGetObserverByName) { | 
|  | auto* first_observer = service()->GetObserverByName(kFirstObserverName); | 
|  | auto* second_observer = service()->GetObserverByName(kSecondObserverName); | 
|  | EXPECT_NE(nullptr, first_observer); | 
|  | EXPECT_NE(nullptr, second_observer); | 
|  | EXPECT_NE(first_observer, second_observer); | 
|  | EXPECT_EQ(nullptr, service()->GetObserverByName("NonExistentObserverName")); | 
|  | } | 
|  |  | 
|  | }  // namespace ash |