| // 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 |