// // Copyright (C) 2012 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "shill/power_manager.h" #include #include #include #include #include #include #include "shill/mock_control.h" #include "shill/mock_event_dispatcher.h" #include "shill/mock_metrics.h" #include "shill/mock_power_manager_proxy.h" #include "shill/power_manager_proxy_interface.h" using base::Bind; using base::Unretained; using std::map; using std::string; using testing::_; using testing::DoAll; using testing::IgnoreResult; using testing::InvokeWithoutArgs; using testing::Mock; using testing::Return; using testing::SetArgumentPointee; using testing::Test; namespace shill { namespace { class FakeControl : public MockControl { public: FakeControl() : delegate_(nullptr), power_manager_proxy_raw_(new MockPowerManagerProxy), power_manager_proxy_(power_manager_proxy_raw_) {} virtual PowerManagerProxyInterface* CreatePowerManagerProxy( PowerManagerProxyDelegate* delegate, const base::Closure& service_appeared_callback, const base::Closure& service_vanished_callback) { CHECK(power_manager_proxy_); delegate_ = delegate; // Passes ownership. return power_manager_proxy_.release(); } PowerManagerProxyDelegate* delegate() const { return delegate_; } // Can not guarantee that the returned object is alive. MockPowerManagerProxy* power_manager_proxy() const { return power_manager_proxy_raw_; } private: PowerManagerProxyDelegate* delegate_; MockPowerManagerProxy* const power_manager_proxy_raw_; std::unique_ptr power_manager_proxy_; }; } // namespace class PowerManagerTest : public Test { public: static const char kDescription[]; static const char kDarkDescription[]; static const char kPowerManagerDefaultOwner[]; static const int kSuspendId1 = 123; static const int kSuspendId2 = 456; static const int kDelayId = 4; static const int kDelayId2 = 5; PowerManagerTest() : kTimeout(base::TimeDelta::FromSeconds(3)), power_manager_(&dispatcher_, &control_), power_manager_proxy_(control_.power_manager_proxy()), delegate_(control_.delegate()) { suspend_imminent_callback_ = Bind(&PowerManagerTest::SuspendImminentAction, Unretained(this)); suspend_done_callback_ = Bind(&PowerManagerTest::SuspendDoneAction, Unretained(this)); dark_suspend_imminent_callback_ = Bind(&PowerManagerTest::DarkSuspendImminentAction, Unretained(this)); } MOCK_METHOD0(SuspendImminentAction, void()); MOCK_METHOD0(SuspendDoneAction, void()); MOCK_METHOD0(DarkSuspendImminentAction, void()); protected: virtual void SetUp() { power_manager_.Start(kTimeout, suspend_imminent_callback_, suspend_done_callback_, dark_suspend_imminent_callback_); } virtual void TearDown() { power_manager_.Stop(); } void AddProxyExpectationForRegisterSuspendDelay(int delay_id, bool return_value) { EXPECT_CALL(*power_manager_proxy_, RegisterSuspendDelay(kTimeout, kDescription, _)) .WillOnce(DoAll(SetArgumentPointee<2>(delay_id), Return(return_value))); } void AddProxyExpectationForUnregisterSuspendDelay(int delay_id, bool return_value) { EXPECT_CALL(*power_manager_proxy_, UnregisterSuspendDelay(delay_id)) .WillOnce(Return(return_value)); } void AddProxyExpectationForReportSuspendReadiness(int delay_id, int suspend_id, bool return_value) { EXPECT_CALL(*power_manager_proxy_, ReportSuspendReadiness(delay_id, suspend_id)) .WillOnce(Return(return_value)); } void AddProxyExpectationForRecordDarkResumeWakeReason( const string& wake_reason, bool return_value) { EXPECT_CALL(*power_manager_proxy_, RecordDarkResumeWakeReason(wake_reason)) .WillOnce(Return(return_value)); } void AddProxyExpectationForRegisterDarkSuspendDelay(int delay_id, bool return_value) { EXPECT_CALL(*power_manager_proxy_, RegisterDarkSuspendDelay(kTimeout, kDarkDescription, _)) .WillOnce(DoAll(SetArgumentPointee<2>(delay_id), Return(return_value))); } void AddProxyExpectationForReportDarkSuspendReadiness(int delay_id, int suspend_id, bool return_value) { EXPECT_CALL(*power_manager_proxy_, ReportDarkSuspendReadiness(delay_id, suspend_id)) .WillOnce(Return(return_value)); } void AddProxyExpectationForUnregisterDarkSuspendDelay(int delay_id, bool return_value) { EXPECT_CALL(*power_manager_proxy_, UnregisterDarkSuspendDelay(delay_id)) .WillOnce(Return(return_value)); } void RegisterSuspendDelays() { AddProxyExpectationForRegisterSuspendDelay(kDelayId, true); AddProxyExpectationForRegisterDarkSuspendDelay(kDelayId, true); OnPowerManagerAppeared(); Mock::VerifyAndClearExpectations(power_manager_proxy_); } void OnSuspendImminent(int suspend_id) { control_.delegate()->OnSuspendImminent(suspend_id); EXPECT_TRUE(power_manager_.suspending()); } void OnSuspendDone(int suspend_id) { control_.delegate()->OnSuspendDone(suspend_id); EXPECT_FALSE(power_manager_.suspending()); } void OnDarkSuspendImminent(int suspend_id) { control_.delegate()->OnDarkSuspendImminent(suspend_id); } void OnPowerManagerAppeared() { power_manager_.OnPowerManagerAppeared(); } void OnPowerManagerVanished() { power_manager_.OnPowerManagerVanished(); } // This is non-static since it's a non-POD type. const base::TimeDelta kTimeout; MockEventDispatcher dispatcher_; FakeControl control_; PowerManager power_manager_; MockPowerManagerProxy* const power_manager_proxy_; PowerManagerProxyDelegate* const delegate_; PowerManager::SuspendImminentCallback suspend_imminent_callback_; PowerManager::SuspendDoneCallback suspend_done_callback_; PowerManager::DarkSuspendImminentCallback dark_suspend_imminent_callback_; }; const char PowerManagerTest::kDescription[] = "shill"; const char PowerManagerTest::kDarkDescription[] = "shill"; const char PowerManagerTest::kPowerManagerDefaultOwner[] = "PowerManagerDefaultOwner"; TEST_F(PowerManagerTest, SuspendingState) { const int kSuspendId = 3; EXPECT_FALSE(power_manager_.suspending()); OnSuspendImminent(kSuspendId); EXPECT_TRUE(power_manager_.suspending()); OnSuspendDone(kSuspendId); EXPECT_FALSE(power_manager_.suspending()); } TEST_F(PowerManagerTest, RegisterSuspendDelayFailure) { AddProxyExpectationForRegisterSuspendDelay(kDelayId, false); OnPowerManagerAppeared(); Mock::VerifyAndClearExpectations(power_manager_proxy_); // Outstanding shill callbacks should still be invoked. // - suspend_done_callback: If powerd died in the middle of a suspend // we want to wake shill up with suspend_done_action, so this callback // should be invoked anyway. // See PowerManagerTest::PowerManagerDiedInSuspend and // PowerManagerTest::PowerManagerReappearedInSuspend. EXPECT_CALL(*this, SuspendDoneAction()); // - suspend_imminent_callback: The only case this can happen is if this // callback was put on the queue, and then powerd reappeared, but we failed // to registered a suspend delay with it. // It is safe to go through the suspend_imminent -> timeout -> suspend_done // path in this black swan case. EXPECT_CALL(*this, SuspendImminentAction()); OnSuspendImminent(kSuspendId1); OnSuspendDone(kSuspendId1); Mock::VerifyAndClearExpectations(this); } TEST_F(PowerManagerTest, RegisterDarkSuspendDelayFailure) { AddProxyExpectationForRegisterDarkSuspendDelay(kDelayId, false); OnPowerManagerAppeared(); Mock::VerifyAndClearExpectations(power_manager_proxy_); // Outstanding dark suspend imminent signal should be ignored, since we // probably won't have time to cleanly do dark resume actions. Might as well // ignore the signal. EXPECT_CALL(*this, DarkSuspendImminentAction()).Times(0); OnDarkSuspendImminent(kSuspendId1); } TEST_F(PowerManagerTest, ReportSuspendReadinessFailure) { RegisterSuspendDelays(); EXPECT_CALL(*this, SuspendImminentAction()); OnSuspendImminent(kSuspendId1); AddProxyExpectationForReportSuspendReadiness(kDelayId, kSuspendId1, false); EXPECT_FALSE(power_manager_.ReportSuspendReadiness()); } TEST_F(PowerManagerTest, RecordDarkResumeWakeReasonFailure) { const string kWakeReason = "WiFi.Disconnect"; RegisterSuspendDelays(); EXPECT_CALL(*this, DarkSuspendImminentAction()); OnDarkSuspendImminent(kSuspendId1); AddProxyExpectationForRecordDarkResumeWakeReason(kWakeReason, false); EXPECT_FALSE(power_manager_.RecordDarkResumeWakeReason(kWakeReason)); } TEST_F(PowerManagerTest, RecordDarkResumeWakeReasonSuccess) { const string kWakeReason = "WiFi.Disconnect"; RegisterSuspendDelays(); EXPECT_CALL(*this, DarkSuspendImminentAction()); OnDarkSuspendImminent(kSuspendId1); AddProxyExpectationForRecordDarkResumeWakeReason(kWakeReason, true); EXPECT_TRUE(power_manager_.RecordDarkResumeWakeReason(kWakeReason)); } TEST_F(PowerManagerTest, ReportDarkSuspendReadinessFailure) { RegisterSuspendDelays(); EXPECT_CALL(*this, DarkSuspendImminentAction()); OnDarkSuspendImminent(kSuspendId1); AddProxyExpectationForReportDarkSuspendReadiness(kDelayId, kSuspendId1, false); EXPECT_FALSE(power_manager_.ReportDarkSuspendReadiness()); } TEST_F(PowerManagerTest, ReportSuspendReadinessFailsOutsideSuspend) { RegisterSuspendDelays(); EXPECT_CALL(*power_manager_proxy_, ReportSuspendReadiness(_, _)).Times(0); EXPECT_FALSE(power_manager_.ReportSuspendReadiness()); } TEST_F(PowerManagerTest, ReportSuspendReadinessSynchronous) { // Verifies that a synchronous ReportSuspendReadiness call by shill on a // SuspendImminent callback is routed back to powerd. RegisterSuspendDelays(); EXPECT_CALL(*power_manager_proxy_, ReportSuspendReadiness(_, _)) .WillOnce(Return(true)); EXPECT_CALL(*this, SuspendImminentAction()) .WillOnce(IgnoreResult(InvokeWithoutArgs( &power_manager_, &PowerManager::ReportSuspendReadiness))); OnSuspendImminent(kSuspendId1); } TEST_F(PowerManagerTest, ReportDarkSuspendReadinessSynchronous) { // Verifies that a synchronous ReportDarkSuspendReadiness call by shill on a // DarkSuspendImminent callback is routed back to powerd. RegisterSuspendDelays(); EXPECT_CALL(*power_manager_proxy_, ReportDarkSuspendReadiness(_, _)) .WillOnce(Return(true)); EXPECT_CALL(*this, DarkSuspendImminentAction()) .WillOnce(IgnoreResult(InvokeWithoutArgs( &power_manager_, &PowerManager::ReportDarkSuspendReadiness))); OnDarkSuspendImminent(kSuspendId1); } TEST_F(PowerManagerTest, Stop) { RegisterSuspendDelays(); AddProxyExpectationForUnregisterSuspendDelay(kDelayId, true); AddProxyExpectationForUnregisterDarkSuspendDelay(kDelayId, true); power_manager_.Stop(); } TEST_F(PowerManagerTest, StopFailure) { RegisterSuspendDelays(); AddProxyExpectationForUnregisterSuspendDelay(kDelayId, false); power_manager_.Stop(); Mock::VerifyAndClearExpectations(power_manager_proxy_); // As a result, callbacks should still be invoked. EXPECT_CALL(*this, SuspendImminentAction()); EXPECT_CALL(*this, SuspendDoneAction()); OnSuspendImminent(kSuspendId1); OnSuspendDone(kSuspendId1); } TEST_F(PowerManagerTest, OnPowerManagerReappeared) { RegisterSuspendDelays(); // Check that we re-register suspend delay on powerd restart. AddProxyExpectationForRegisterSuspendDelay(kDelayId2, true); AddProxyExpectationForRegisterDarkSuspendDelay(kDelayId2, true); OnPowerManagerVanished(); OnPowerManagerAppeared(); Mock::VerifyAndClearExpectations(power_manager_proxy_); // Check that a |ReportSuspendReadiness| message is sent with the new delay // id. EXPECT_CALL(*this, SuspendImminentAction()); OnSuspendImminent(kSuspendId1); AddProxyExpectationForReportSuspendReadiness(kDelayId2, kSuspendId1, true); EXPECT_TRUE(power_manager_.ReportSuspendReadiness()); Mock::VerifyAndClearExpectations(power_manager_proxy_); // Check that a |ReportDarkSuspendReadiness| message is sent with the new // delay id. EXPECT_CALL(*this, DarkSuspendImminentAction()); OnDarkSuspendImminent(kSuspendId1); AddProxyExpectationForReportDarkSuspendReadiness(kDelayId2, kSuspendId1, true); EXPECT_TRUE(power_manager_.ReportDarkSuspendReadiness()); } TEST_F(PowerManagerTest, PowerManagerDiedInSuspend) { RegisterSuspendDelays(); EXPECT_CALL(*this, SuspendImminentAction()); OnSuspendImminent(kSuspendId1); Mock::VerifyAndClearExpectations(this); EXPECT_CALL(*this, SuspendDoneAction()); OnPowerManagerVanished(); EXPECT_FALSE(power_manager_.suspending()); } TEST_F(PowerManagerTest, PowerManagerReappearedInSuspend) { RegisterSuspendDelays(); EXPECT_CALL(*this, SuspendImminentAction()); OnSuspendImminent(kSuspendId1); Mock::VerifyAndClearExpectations(this); AddProxyExpectationForRegisterSuspendDelay(kDelayId2, true); AddProxyExpectationForRegisterDarkSuspendDelay(kDelayId2, true); EXPECT_CALL(*this, SuspendDoneAction()); OnPowerManagerVanished(); OnPowerManagerAppeared(); EXPECT_FALSE(power_manager_.suspending()); Mock::VerifyAndClearExpectations(this); // Let's check a normal suspend request after the fact. EXPECT_CALL(*this, SuspendImminentAction()); OnSuspendImminent(kSuspendId2); } } // namespace shill