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