Commit e29a8f33 authored by Abhishek Bhardwaj's avatar Abhishek Bhardwaj Committed by Commit Bot

PowerManagerClient: Make fake use mock ticks

This change makes FakePowerManagerClient now use mock ticks for timers.
This means that timer expiration can be tested more strigently in tests
instead of earlier tests where only timer expiration was checked and not
the time when they expired.

BUG=962638
TEST=Unit tests.

Change-Id: Ic6b94e927dff2b55d9b622d77f663e377be7a4f8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1610224
Commit-Queue: Abhishek Bhardwaj <abhishekbh@chromium.org>
Auto-Submit: Abhishek Bhardwaj <abhishekbh@chromium.org>
Reviewed-by: default avatarDan Erat <derat@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659425}
parent 7d46b886
...@@ -10,65 +10,52 @@ ...@@ -10,65 +10,52 @@
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/dbus/power/power_manager_client.h" #include "chromeos/dbus/power/power_manager_client.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace chromeos { namespace chromeos {
namespace {
// Returns true iff |Start| on |timer| succeeds and timer expiration occurs too.
// The underlying fake power manager implementation expires the timer
// immediately and the test doesn't sleep.
bool CheckStartTimerAndExpiration(NativeTimer* timer,
base::TimeTicks absolute_expiration_ticks) {
base::RunLoop start_timer_loop;
base::RunLoop expiration_loop;
bool start_timer_result = false;
bool expiration_result = false;
timer->Start(
absolute_expiration_ticks,
base::BindOnce(
[](bool* result_out, base::OnceClosure quit_closure) {
*result_out = true;
std::move(quit_closure).Run();
},
&expiration_result, expiration_loop.QuitClosure()),
base::BindOnce(
[](bool* result_out, base::OnceClosure quit_closure, bool result) {
*result_out = result;
std::move(quit_closure).Run();
},
&start_timer_result, start_timer_loop.QuitClosure()));
start_timer_loop.Run();
if (!start_timer_result) {
return false;
}
// Run until timer expiration and check for the result.
expiration_loop.Run();
if (!expiration_result) {
return false;
}
return true;
}
} // namespace
class NativeTimerTest : public testing::Test { class NativeTimerTest : public testing::Test {
public: public:
NativeTimerTest() NativeTimerTest()
: scoped_task_environment_( : scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::IO) {} base::test::ScopedTaskEnvironment::MainThreadType::IO_MOCK_TIME) {}
~NativeTimerTest() override = default; ~NativeTimerTest() override = default;
// testing::Test: // testing::Test:
void SetUp() override { PowerManagerClient::InitializeFake(); } void SetUp() override {
PowerManagerClient::InitializeFake();
FakePowerManagerClient::Get()->set_tick_clock(
scoped_task_environment_.GetMockTickClock());
}
void TearDown() override { PowerManagerClient::Shutdown(); } void TearDown() override { PowerManagerClient::Shutdown(); }
protected: protected:
// Returns true iff |Start| on |timer| succeeds and timer expiration occurs
// too. The underlying fake power manager implementation expires the timer
bool CheckStartTimerAndExpiration(NativeTimer* timer, base::TimeDelta delay) {
base::RunLoop start_timer_loop;
base::RunLoop expiration_loop;
bool start_timer_result = false;
bool expiration_result = false;
timer->Start(
scoped_task_environment_.GetMockTickClock()->NowTicks() + delay,
base::BindOnce([](bool* result_out) { *result_out = true; },
&expiration_result),
base::BindOnce(
[](bool* result_out, bool result) { *result_out = result; },
&start_timer_result));
// Both starting the timer and timer firing should succeed.
scoped_task_environment_.FastForwardBy(delay);
if (!start_timer_result)
return false;
return expiration_result;
}
base::test::ScopedTaskEnvironment scoped_task_environment_; base::test::ScopedTaskEnvironment scoped_task_environment_;
private: private:
...@@ -84,7 +71,7 @@ TEST_F(NativeTimerTest, CheckCreateFailure) { ...@@ -84,7 +71,7 @@ TEST_F(NativeTimerTest, CheckCreateFailure) {
// Starting the timer should fail as timer creation failed. // Starting the timer should fail as timer creation failed.
EXPECT_FALSE(CheckStartTimerAndExpiration( EXPECT_FALSE(CheckStartTimerAndExpiration(
&timer, base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000))); &timer, base::TimeDelta::FromMilliseconds(1000)));
} }
TEST_F(NativeTimerTest, CheckCreateAndStartTimer) { TEST_F(NativeTimerTest, CheckCreateAndStartTimer) {
...@@ -95,12 +82,12 @@ TEST_F(NativeTimerTest, CheckCreateAndStartTimer) { ...@@ -95,12 +82,12 @@ TEST_F(NativeTimerTest, CheckCreateAndStartTimer) {
// Start timer and check if starting the timer and its expiration succeeded. // Start timer and check if starting the timer and its expiration succeeded.
EXPECT_TRUE(CheckStartTimerAndExpiration( EXPECT_TRUE(CheckStartTimerAndExpiration(
&timer, base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000))); &timer, base::TimeDelta::FromMilliseconds(1000)));
// Start another timer and check if starting the timer and its expiration // Start another timer and check if starting the timer and its expiration
// succeeded. // succeeded.
EXPECT_TRUE(CheckStartTimerAndExpiration( EXPECT_TRUE(CheckStartTimerAndExpiration(
&timer, base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000))); &timer, base::TimeDelta::FromMilliseconds(1000)));
} }
} // namespace chromeos } // namespace chromeos
...@@ -53,6 +53,18 @@ power_manager::BacklightBrightnessChange_Cause RequestCauseToChangeCause( ...@@ -53,6 +53,18 @@ power_manager::BacklightBrightnessChange_Cause RequestCauseToChangeCause(
return power_manager::BacklightBrightnessChange_Cause_USER_REQUEST; return power_manager::BacklightBrightnessChange_Cause_USER_REQUEST;
} }
// Copied from Chrome's //base/time/time_now_posix.cc.
// Returns count of |clk_id| in the form of a time delta. Returns an empty
// time delta if |clk_id| isn't present on the system.
base::TimeDelta ClockNow(clockid_t clk_id) {
struct timespec ts;
if (clock_gettime(clk_id, &ts) != 0) {
NOTREACHED() << "clock_gettime(" << clk_id << ") failed.";
return base::TimeDelta();
}
return base::TimeDelta::FromTimeSpec(ts);
}
} // namespace } // namespace
// static // static
...@@ -62,7 +74,7 @@ FakePowerManagerClient* FakePowerManagerClient::Get() { ...@@ -62,7 +74,7 @@ FakePowerManagerClient* FakePowerManagerClient::Get() {
} }
FakePowerManagerClient::FakePowerManagerClient() FakePowerManagerClient::FakePowerManagerClient()
: props_(power_manager::PowerSupplyProperties()) { : props_(power_manager::PowerSupplyProperties()), tick_clock_(nullptr) {
CHECK(!g_instance); CHECK(!g_instance);
g_instance = this; g_instance = this;
...@@ -323,8 +335,13 @@ void FakePowerManagerClient::StartArcTimer( ...@@ -323,8 +335,13 @@ void FakePowerManagerClient::StartArcTimer(
// Post task to write to |clock_id|'s expiration fd. This will simulate the // Post task to write to |clock_id|'s expiration fd. This will simulate the
// timer expiring to the caller. Ignore delaying by // timer expiring to the caller. Ignore delaying by
// |absolute_expiration_time| for test purposes. // |absolute_expiration_time| for test purposes.
base::ThreadTaskRunnerHandle::Get()->PostTask( base::TimeTicks current_ticks = GetCurrentBootTime();
FROM_HERE, base::BindOnce(&ArcTimerExpirationCallback, it->second.get())); base::TimeDelta task_delay;
if (absolute_expiration_time > current_ticks)
task_delay = absolute_expiration_time - current_ticks;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::BindOnce(&ArcTimerExpirationCallback, it->second.get()),
task_delay);
} }
void FakePowerManagerClient::DeleteArcTimers(const std::string& tag, void FakePowerManagerClient::DeleteArcTimers(const std::string& tag,
...@@ -459,4 +476,11 @@ bool FakePowerManagerClient::ApplyPendingScreenBrightnessChange() { ...@@ -459,4 +476,11 @@ bool FakePowerManagerClient::ApplyPendingScreenBrightnessChange() {
return true; return true;
} }
// Returns time ticks from boot including time ticks spent during sleeping.
base::TimeTicks FakePowerManagerClient::GetCurrentBootTime() {
if (tick_clock_)
return tick_clock_->NowTicks();
return base::TimeTicks() + ClockNow(CLOCK_BOOTTIME);
}
} // namespace chromeos } // namespace chromeos
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chromeos/dbus/power/power_manager_client.h" #include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/dbus/power_manager/backlight.pb.h" #include "chromeos/dbus/power_manager/backlight.pb.h"
...@@ -175,6 +176,9 @@ class COMPONENT_EXPORT(DBUS_POWER) FakePowerManagerClient ...@@ -175,6 +176,9 @@ class COMPONENT_EXPORT(DBUS_POWER) FakePowerManagerClient
// return false if there are no pending brightness changes. // return false if there are no pending brightness changes.
bool ApplyPendingScreenBrightnessChange(); bool ApplyPendingScreenBrightnessChange();
// Returns time ticks from boot including time ticks spent during sleeping.
base::TimeTicks GetCurrentBootTime();
// Sets the screen brightness percent to be returned. // Sets the screen brightness percent to be returned.
// The nullopt |percent| means an error. In case of success, // The nullopt |percent| means an error. In case of success,
// |percent| must be in the range of [0, 100]. // |percent| must be in the range of [0, 100].
...@@ -186,6 +190,11 @@ class COMPONENT_EXPORT(DBUS_POWER) FakePowerManagerClient ...@@ -186,6 +190,11 @@ class COMPONENT_EXPORT(DBUS_POWER) FakePowerManagerClient
keyboard_brightness_percent_ = percent; keyboard_brightness_percent_ = percent;
} }
// Sets |tick_clock| to |tick_clock_|.
void set_tick_clock(const base::TickClock* tick_clock) {
tick_clock_ = tick_clock;
}
private: private:
// Notifies |observers_| that |props_| has been updated. // Notifies |observers_| that |props_| has been updated.
void NotifyObservers(); void NotifyObservers();
...@@ -279,6 +288,9 @@ class COMPONENT_EXPORT(DBUS_POWER) FakePowerManagerClient ...@@ -279,6 +288,9 @@ class COMPONENT_EXPORT(DBUS_POWER) FakePowerManagerClient
// If non-empty, called by NotifyUserActivity(). // If non-empty, called by NotifyUserActivity().
base::RepeatingClosure user_activity_callback_; base::RepeatingClosure user_activity_callback_;
// Clock to use to calculate time ticks. Used for ArcTimer related APIs.
const base::TickClock* tick_clock_;
// Note: This should remain the last member so it'll be destroyed and // Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed. // invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<FakePowerManagerClient> weak_ptr_factory_{this}; base::WeakPtrFactory<FakePowerManagerClient> weak_ptr_factory_{this};
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "services/device/public/mojom/constants.mojom.h" #include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h" #include "services/device/public/mojom/wake_lock_provider.mojom.h"
...@@ -35,11 +36,6 @@ base::TimeDelta ClockNow(clockid_t clk_id) { ...@@ -35,11 +36,6 @@ base::TimeDelta ClockNow(clockid_t clk_id) {
return base::TimeDelta::FromTimeSpec(ts); return base::TimeDelta::FromTimeSpec(ts);
} }
// Returns time ticks from boot including time ticks spent during sleeping.
base::TimeTicks GetCurrentBootTime() {
return base::TimeTicks() + ClockNow(CLOCK_BOOTTIME);
}
} // namespace } // namespace
PowerManagerProviderImpl::PowerManagerProviderImpl( PowerManagerProviderImpl::PowerManagerProviderImpl(
...@@ -97,6 +93,12 @@ void PowerManagerProviderImpl::ReleaseWakeLock() { ...@@ -97,6 +93,12 @@ void PowerManagerProviderImpl::ReleaseWakeLock() {
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
base::TimeTicks PowerManagerProviderImpl::GetCurrentBootTime() {
if (tick_clock_)
return tick_clock_->NowTicks();
return base::TimeTicks() + ClockNow(CLOCK_BOOTTIME);
}
void PowerManagerProviderImpl::AddWakeAlarmOnMainThread( void PowerManagerProviderImpl::AddWakeAlarmOnMainThread(
AlarmId id, AlarmId id,
base::TimeTicks absolute_expiration_time, base::TimeTicks absolute_expiration_time,
......
...@@ -54,10 +54,18 @@ class COMPONENT_EXPORT(ASSISTANT_SERVICE) PowerManagerProviderImpl ...@@ -54,10 +54,18 @@ class COMPONENT_EXPORT(ASSISTANT_SERVICE) PowerManagerProviderImpl
void AcquireWakeLock() override; void AcquireWakeLock() override;
void ReleaseWakeLock() override; void ReleaseWakeLock() override;
void set_tick_clock_for_testing(const base::TickClock* tick_clock) {
DCHECK(tick_clock);
tick_clock_ = tick_clock;
}
private: private:
using CallbackAndTimer = using CallbackAndTimer =
std::pair<assistant_client::Callback0, std::unique_ptr<NativeTimer>>; std::pair<assistant_client::Callback0, std::unique_ptr<NativeTimer>>;
// Returns time ticks from boot including time ticks during sleeping.
base::TimeTicks GetCurrentBootTime();
// Creates a native timer by calling |NativeTimer::Create|. Runs on // Creates a native timer by calling |NativeTimer::Create|. Runs on
// |main_thread_task_runner_|. // |main_thread_task_runner_|.
void AddWakeAlarmOnMainThread(AlarmId id, void AddWakeAlarmOnMainThread(AlarmId id,
...@@ -102,6 +110,9 @@ class COMPONENT_EXPORT(ASSISTANT_SERVICE) PowerManagerProviderImpl ...@@ -102,6 +110,9 @@ class COMPONENT_EXPORT(ASSISTANT_SERVICE) PowerManagerProviderImpl
// order to use Chrome APIs safely. // order to use Chrome APIs safely.
const scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner_; const scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner_;
// Clock to use to calculate time ticks. Set and used only for testing.
const base::TickClock* tick_clock_ = nullptr;
base::WeakPtrFactory<PowerManagerProviderImpl> weak_factory_; base::WeakPtrFactory<PowerManagerProviderImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PowerManagerProviderImpl); DISALLOW_COPY_AND_ASSIGN(PowerManagerProviderImpl);
......
...@@ -28,16 +28,20 @@ class PowerManagerProviderImplTest : public testing::Test { ...@@ -28,16 +28,20 @@ class PowerManagerProviderImplTest : public testing::Test {
public: public:
PowerManagerProviderImplTest() PowerManagerProviderImplTest()
: scoped_task_environment_( : scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::IO), base::test::ScopedTaskEnvironment::MainThreadType::IO_MOCK_TIME),
wake_lock_provider_( wake_lock_provider_(
connector_factory_.RegisterInstance(device::mojom::kServiceName)) {} connector_factory_.RegisterInstance(device::mojom::kServiceName)) {}
~PowerManagerProviderImplTest() override = default; ~PowerManagerProviderImplTest() override = default;
void SetUp() override { void SetUp() override {
chromeos::PowerManagerClient::InitializeFake(); chromeos::PowerManagerClient::InitializeFake();
FakePowerManagerClient::Get()->set_tick_clock(
scoped_task_environment_.GetMockTickClock());
power_manager_provider_impl_ = std::make_unique<PowerManagerProviderImpl>( power_manager_provider_impl_ = std::make_unique<PowerManagerProviderImpl>(
connector_factory_.GetDefaultConnector(), connector_factory_.GetDefaultConnector(),
scoped_task_environment_.GetMainThreadTaskRunner()); scoped_task_environment_.GetMainThreadTaskRunner());
power_manager_provider_impl_->set_tick_clock_for_testing(
scoped_task_environment_.GetMockTickClock());
} }
void TearDown() override { void TearDown() override {
...@@ -87,21 +91,20 @@ class PowerManagerProviderImplTest : public testing::Test { ...@@ -87,21 +91,20 @@ class PowerManagerProviderImplTest : public testing::Test {
bool CheckAddWakeAlarmAndExpiration(uint64_t relative_time_ms, bool CheckAddWakeAlarmAndExpiration(uint64_t relative_time_ms,
uint64_t max_delay_ms) { uint64_t max_delay_ms) {
// Schedule wake alarm and check if valid id is returned and timer callback // Schedule wake alarm and check if valid id is returned and timer callback
// is fired. Fake power manager ensures that the timer is notified instantly // is fired.
// in tests and the test doesn't sleep.
base::RunLoop run_loop;
bool result = false; bool result = false;
assistant_client::Callback0 wake_alarm_expiration_cb([&]() { assistant_client::Callback0 wake_alarm_expiration_cb(
result = true; [&result]() { result = true; });
run_loop.QuitClosure().Run();
});
assistant_client::PowerManagerProvider::AlarmId id = assistant_client::PowerManagerProvider::AlarmId id =
power_manager_provider_impl_->AddWakeAlarm( power_manager_provider_impl_->AddWakeAlarm(
relative_time_ms, max_delay_ms, relative_time_ms, max_delay_ms,
std::move(wake_alarm_expiration_cb)); std::move(wake_alarm_expiration_cb));
run_loop.Run(); scoped_task_environment_.FastForwardBy(
// Assistant client requires wake alarm ids to be > 0. base::TimeDelta::FromMilliseconds(relative_time_ms));
return id > 0UL && result;
if (id <= 0UL)
return false;
return result;
} }
private: private:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment