chromium/chrome/browser/ash/power/auto_screen_brightness/brightness_monitor_impl_unittest.cc

// Copyright 2018 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/power/auto_screen_brightness/brightness_monitor_impl.h"

#include "ash/constants/ash_features.h"
#include "base/memory/ptr_util.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/dbus/power_manager/backlight.pb.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {
namespace power {
namespace auto_screen_brightness {

namespace {

class TestObserver : public BrightnessMonitor::Observer {
 public:
  TestObserver() {}

  TestObserver(const TestObserver&) = delete;
  TestObserver& operator=(const TestObserver&) = delete;

  ~TestObserver() override = default;

  // BrightnessMonitor::Observer overrides:
  void OnBrightnessMonitorInitialized(bool success) override {
    status_ = std::optional<BrightnessMonitor::Status>(
        success ? BrightnessMonitor::Status::kSuccess
                : BrightnessMonitor::Status::kDisabled);
  }

  void OnUserBrightnessChanged(double old_brightness_percent,
                               double new_brightness_percent) override {
    old_brightness_percent_ = old_brightness_percent;
    new_brightness_percent_ = new_brightness_percent;
    ++num_brightness_changes_;
  }

  void OnUserBrightnessChangeRequested() override {
    ++num_user_brightness_change_requested_;
  }

  double old_brightness_percent() { return old_brightness_percent_; }
  double new_brightness_percent() { return new_brightness_percent_; }
  int num_brightness_changes() { return num_brightness_changes_; }
  int num_user_brightness_change_requested() {
    return num_user_brightness_change_requested_;
  }

  BrightnessMonitor::Status status() {
    CHECK(status_);
    return status_.value();
  }

 private:
  double old_brightness_percent_ = -1;
  double new_brightness_percent_ = -1;
  int num_brightness_changes_ = 0;
  int num_user_brightness_change_requested_ = 0;
  std::optional<BrightnessMonitor::Status> status_;
};
}  // namespace

class BrightnessMonitorImplTest : public testing::Test {
 public:
  BrightnessMonitorImplTest()
      : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}

  BrightnessMonitorImplTest(const BrightnessMonitorImplTest&) = delete;
  BrightnessMonitorImplTest& operator=(const BrightnessMonitorImplTest&) =
      delete;

  ~BrightnessMonitorImplTest() override {}

  // testing::Test:
  void SetUp() override { chromeos::PowerManagerClient::InitializeFake(); }

  void TearDown() override {
    test_observer_.reset();
    monitor_.reset();
    chromeos::PowerManagerClient::Shutdown();
    base::ThreadPoolInstance::Get()->FlushForTesting();
  }

  // Creates and initializes |monitor_| and optionally sets initial brightness
  // on fake power manager client.
  void SetUpBrightnessMonitor(
      double init_brightness,
      const std::map<std::string, std::string>& params = {}) {
    if (init_brightness >= 0) {
      power_manager::SetBacklightBrightnessRequest request;
      request.set_percent(init_brightness);
      chromeos::PowerManagerClient::Get()->SetScreenBrightness(request);
    }

    if (!params.empty()) {
      scoped_feature_list_.InitAndEnableFeatureWithParameters(
          features::kAutoScreenBrightness, params);
    }

    monitor_ = std::make_unique<BrightnessMonitorImpl>();
    monitor_->Init();
    test_observer_ = std::make_unique<TestObserver>();
    monitor_->AddObserver(test_observer_.get());
    task_environment_.RunUntilIdle();
  }

 protected:
  void ReportBrightnessChangeEvent(
      double level,
      power_manager::BacklightBrightnessChange_Cause cause) {
    power_manager::BacklightBrightnessChange change;
    change.set_percent(level);
    change.set_cause(cause);
    static_cast<chromeos::FakePowerManagerClient*>(
        chromeos::PowerManagerClient::Get())
        ->SendScreenBrightnessChanged(change);
    task_environment_.RunUntilIdle();
  }

  base::test::TaskEnvironment task_environment_;
  base::HistogramTester histogram_tester_;
  std::unique_ptr<BrightnessMonitorImpl> monitor_;
  std::unique_ptr<TestObserver> test_observer_;
  base::test::ScopedFeatureList scoped_feature_list_;
};

TEST_F(BrightnessMonitorImplTest, ReportSuccess) {
  SetUpBrightnessMonitor(10);
  task_environment_.FastForwardUntilNoTasksRemain();

  histogram_tester_.ExpectUniqueSample(
      "AutoScreenBrightness.BrightnessMonitorStatus",
      static_cast<int>(BrightnessMonitor::Status::kSuccess), 1);
}

TEST_F(BrightnessMonitorImplTest, ReportDisabled) {
  SetUpBrightnessMonitor(-1);
  task_environment_.FastForwardUntilNoTasksRemain();

  histogram_tester_.ExpectUniqueSample(
      "AutoScreenBrightness.BrightnessMonitorStatus",
      static_cast<int>(BrightnessMonitor::Status::kDisabled), 1);
}

// PowerManagerClient is not set up to return initial brightness, hence
// Status is kDisabled.
TEST_F(BrightnessMonitorImplTest, PowerManagerClientBrightnessUnset) {
  // Do not set initial brightess in FakePowerManagerClient.
  SetUpBrightnessMonitor(-1);
  EXPECT_EQ(BrightnessMonitor::Status::kDisabled, test_observer_->status());

  // User request will be ignored.
  ReportBrightnessChangeEvent(
      20, power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() * 2);
  EXPECT_EQ(0, test_observer_->num_brightness_changes());
  EXPECT_EQ(0, test_observer_->num_user_brightness_change_requested());
}

// Two user brightness adjustments are received with a gap shorter than
// brightness sample delay, hence final brightness is recorded.
TEST_F(BrightnessMonitorImplTest, TwoUserAdjustmentsShortGap) {
  SetUpBrightnessMonitor(10);
  EXPECT_EQ(BrightnessMonitor::Status::kSuccess, test_observer_->status());
  EXPECT_EQ(0, test_observer_->num_brightness_changes());
  EXPECT_EQ(0, test_observer_->num_user_brightness_change_requested());

  // First user-requested brightness adjustment.
  ReportBrightnessChangeEvent(
      20, power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
  EXPECT_EQ(1, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(0, test_observer_->num_brightness_changes());

  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() / 2);
  // Second user-requested brightness adjustment.
  ReportBrightnessChangeEvent(
      30, power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
  EXPECT_EQ(2, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(0, test_observer_->num_brightness_changes());

  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() * 2);

  EXPECT_EQ(2, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(1, test_observer_->num_brightness_changes());
  EXPECT_DOUBLE_EQ(10, test_observer_->old_brightness_percent());
  EXPECT_DOUBLE_EQ(30, test_observer_->new_brightness_percent());
}

// Two user brightness adjustments are received with a gap longer than
// brightness sample delay, hence two brightness changes are recorded.
TEST_F(BrightnessMonitorImplTest, TwoUserAdjustmentsLongGap) {
  SetUpBrightnessMonitor(10, {{"brightness_sample_delay_seconds", "2"}});
  EXPECT_EQ(BrightnessMonitor::Status::kSuccess, test_observer_->status());
  EXPECT_EQ(0, test_observer_->num_brightness_changes());
  EXPECT_EQ(0, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(2, monitor_->GetBrightnessSampleDelayForTesting().InSeconds());

  // First user-requested brightness adjustment.
  ReportBrightnessChangeEvent(
      20, power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
  EXPECT_EQ(1, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(0, test_observer_->num_brightness_changes());

  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() * 2);
  EXPECT_EQ(1, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(1, test_observer_->num_brightness_changes());
  EXPECT_DOUBLE_EQ(10, test_observer_->old_brightness_percent());
  EXPECT_DOUBLE_EQ(20, test_observer_->new_brightness_percent());

  // Second user-requested brightness adjustment.
  ReportBrightnessChangeEvent(
      30, power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
  EXPECT_EQ(2, test_observer_->num_user_brightness_change_requested());
  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() * 2);

  EXPECT_EQ(2, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(2, test_observer_->num_brightness_changes());
  EXPECT_DOUBLE_EQ(20, test_observer_->old_brightness_percent());
  EXPECT_DOUBLE_EQ(30, test_observer_->new_brightness_percent());
}

// A brightness change not triggered by user request, followed by user requested
// change. The gap between the two is shorter than brightness sample delay.
TEST_F(BrightnessMonitorImplTest, NonUserFollowedByUserShortGap) {
  SetUpBrightnessMonitor(10);

  // Non-user.
  ReportBrightnessChangeEvent(
      20, power_manager::BacklightBrightnessChange_Cause_USER_ACTIVITY);
  EXPECT_EQ(0, test_observer_->num_user_brightness_change_requested());
  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() / 2);
  EXPECT_EQ(0, test_observer_->num_brightness_changes());

  // User.
  ReportBrightnessChangeEvent(
      30, power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
  EXPECT_EQ(1, test_observer_->num_user_brightness_change_requested());
  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() * 2);

  EXPECT_EQ(1, test_observer_->num_brightness_changes());
  EXPECT_DOUBLE_EQ(20, test_observer_->old_brightness_percent());
  EXPECT_DOUBLE_EQ(30, test_observer_->new_brightness_percent());
}

// A brightness change not triggered by user request, followed by user requested
// change. The gap between the two is longer than brightness sample delay.
TEST_F(BrightnessMonitorImplTest, NonUserFollowedByUserLongGap) {
  SetUpBrightnessMonitor(10);

  ReportBrightnessChangeEvent(
      20, power_manager::BacklightBrightnessChange_Cause_USER_ACTIVITY);
  EXPECT_EQ(0, test_observer_->num_user_brightness_change_requested());
  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() * 2);
  EXPECT_EQ(0, test_observer_->num_brightness_changes());

  ReportBrightnessChangeEvent(
      30, power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
  EXPECT_EQ(1, test_observer_->num_user_brightness_change_requested());
  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() * 2);

  EXPECT_EQ(1, test_observer_->num_brightness_changes());
  EXPECT_DOUBLE_EQ(20, test_observer_->old_brightness_percent());
  EXPECT_DOUBLE_EQ(30, test_observer_->new_brightness_percent());
}

// A user requested brightness change is received, another non-user triggered
// change is received before timer times out. Followed by another user requested
// change.
TEST_F(BrightnessMonitorImplTest, UserAdjustmentsSeparatedByNonUser) {
  SetUpBrightnessMonitor(10);

  // User request.
  ReportBrightnessChangeEvent(
      20, power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
  EXPECT_EQ(1, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(0, test_observer_->num_brightness_changes());

  // Non-user.
  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() / 2);
  ReportBrightnessChangeEvent(
      30, power_manager::BacklightBrightnessChange_Cause_USER_ACTIVITY);
  EXPECT_EQ(1, test_observer_->num_user_brightness_change_requested());
  // Timer times out immediately to send out brightness change notification.
  EXPECT_EQ(1, test_observer_->num_brightness_changes());
  EXPECT_DOUBLE_EQ(10, test_observer_->old_brightness_percent());
  EXPECT_DOUBLE_EQ(20, test_observer_->new_brightness_percent());

  // Another user request.
  ReportBrightnessChangeEvent(
      40, power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
  EXPECT_EQ(2, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(1, test_observer_->num_brightness_changes());

  task_environment_.FastForwardBy(
      monitor_->GetBrightnessSampleDelayForTesting() * 2);
  EXPECT_EQ(2, test_observer_->num_user_brightness_change_requested());
  EXPECT_EQ(2, test_observer_->num_brightness_changes());
  EXPECT_DOUBLE_EQ(30, test_observer_->old_brightness_percent());
  EXPECT_DOUBLE_EQ(40, test_observer_->new_brightness_percent());
}

}  // namespace auto_screen_brightness
}  // namespace power
}  // namespace ash