| // Copyright 2019 The Chromium OS 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 "power_manager/powerd/system/wakeup_source_identifier.h" | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include <base/files/file_util.h> | 
 | #include <base/files/scoped_temp_dir.h> | 
 | #include <base/strings/string_util.h> | 
 | #include <base/strings/string_number_conversions.h> | 
 | #include <gtest/gtest.h> | 
 |  | 
 | #include "power_manager/common/power_constants.h" | 
 | #include "power_manager/common/util.h" | 
 | #include "power_manager/powerd/system/udev_stub.h" | 
 |  | 
 | namespace power_manager { | 
 | namespace system { | 
 | namespace { | 
 |  | 
 | const char kRandomEventCountPath[] = "wakeup/wakeup45/event_count"; | 
 | const char kTestSysPath[] = "sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/"; | 
 |  | 
 | // Creates |file_path|. Also creates all necessary parent directories. | 
 | void CreateFile(const base::FilePath& file_path) { | 
 |   ASSERT_TRUE(base::CreateDirectory(file_path.DirName())); | 
 |   CHECK_EQ(base::WriteFile(file_path, "", 0), 0); | 
 | } | 
 |  | 
 | void CreatePowerWakeupAttrInDir(const base::FilePath& dir_path) { | 
 |   const base::FilePath wakeup_path = dir_path.Append(kPowerWakeup); | 
 |   CreateFile(wakeup_path); | 
 | } | 
 |  | 
 | void CreateEventCountAttrInSys(const base::FilePath& dir_path) { | 
 |   const base::FilePath event_count_path = | 
 |       dir_path.Append(kRandomEventCountPath); | 
 |   CreateFile(event_count_path); | 
 |   // By default set the event count to 0 | 
 |   ASSERT_TRUE(util::WriteInt64File(event_count_path, 0)); | 
 | } | 
 |  | 
 | void IncrementEventCount(const base::FilePath& dir_path) { | 
 |   const base::FilePath event_count_path = | 
 |       dir_path.Append(kRandomEventCountPath); | 
 |  | 
 |   std::string event_count_str; | 
 |   ASSERT_TRUE(base::ReadFileToString(event_count_path, &event_count_str)); | 
 |   base::TrimWhitespaceASCII(event_count_str, base::TRIM_TRAILING, | 
 |                             &event_count_str); | 
 |   int64_t current_count; | 
 |   ASSERT_TRUE(base::StringToInt64(event_count_str, ¤t_count)); | 
 |  | 
 |   ASSERT_TRUE(util::WriteInt64File(event_count_path, current_count + 1)); | 
 | } | 
 |  | 
 | class WakeupSourceIdentifierTest : public ::testing::Test { | 
 |  public: | 
 |   WakeupSourceIdentifierTest() { | 
 |     CHECK(temp_dir_.CreateUniqueTempDir()); | 
 |     wakeup_device_path_ = temp_dir_.GetPath().Append(kTestSysPath); | 
 |     CreatePowerWakeupAttrInDir(wakeup_device_path_); | 
 |     CreateEventCountAttrInSys(wakeup_device_path_); | 
 |     wakeup_source_identifier_ = | 
 |         std::make_unique<system::WakeupSourceIdentifier>(&udev_); | 
 |   } | 
 |  | 
 |  protected: | 
 |   void SendInputUdevEvent(const UdevEvent::Action action, | 
 |                           const std::string& input_name, | 
 |                           const base::FilePath& wakeup_path) { | 
 |     UdevDeviceInfo input_device_info; | 
 |     input_device_info.subsystem = kInputUdevSubsystem; | 
 |     input_device_info.sysname = input_name; | 
 |     input_device_info.wakeup_device_path = wakeup_path; | 
 |  | 
 |     UdevEvent event; | 
 |     event.action = action; | 
 |     event.device_info = input_device_info; | 
 |     udev_.NotifySubsystemObservers(event); | 
 |   } | 
 |  | 
 |   UdevStub udev_; | 
 |   std::unique_ptr<WakeupSourceIdentifier> wakeup_source_identifier_; | 
 |   base::ScopedTempDir temp_dir_; | 
 |   base::FilePath wakeup_device_path_; | 
 | }; | 
 |  | 
 | TEST_F(WakeupSourceIdentifierTest, TestWakeDueToInputDevice) { | 
 |   // Add first input with |wakeup_device_path_| | 
 |   SendInputUdevEvent(UdevEvent::Action::ADD, "input1", wakeup_device_path_); | 
 |   // Now let us suspend and increment the event count. | 
 |   wakeup_source_identifier_->PrepareForSuspendRequest(); | 
 |   IncrementEventCount(wakeup_device_path_); | 
 |   wakeup_source_identifier_->HandleResume(); | 
 |   EXPECT_TRUE(wakeup_source_identifier_->InputDeviceCausedLastWake()); | 
 | } | 
 |  | 
 | TEST_F(WakeupSourceIdentifierTest, TestAddAndRemoveInputDevice) { | 
 |   // Add first input with |wakeup_device_path_| | 
 |   SendInputUdevEvent(UdevEvent::Action::ADD, "input1", wakeup_device_path_); | 
 |   SendInputUdevEvent(UdevEvent::Action::REMOVE, "input1", wakeup_device_path_); | 
 |  | 
 |   // Now let us suspend and increment the event count. | 
 |   wakeup_source_identifier_->PrepareForSuspendRequest(); | 
 |   IncrementEventCount(wakeup_device_path_); | 
 |   wakeup_source_identifier_->HandleResume(); | 
 |   EXPECT_FALSE(wakeup_source_identifier_->InputDeviceCausedLastWake()); | 
 | } | 
 |  | 
 | TEST_F(WakeupSourceIdentifierTest, TestMultipleInputDevicesWithSameWakePath) { | 
 |   // Add first input with |wakeup_device_path_| | 
 |   SendInputUdevEvent(UdevEvent::Action::ADD, "input1", wakeup_device_path_); | 
 |   SendInputUdevEvent(UdevEvent::Action::ADD, "input2", wakeup_device_path_); | 
 |   SendInputUdevEvent(UdevEvent::Action::REMOVE, "input1", wakeup_device_path_); | 
 |   // Now let us suspend and increment the event count. | 
 |   wakeup_source_identifier_->PrepareForSuspendRequest(); | 
 |   IncrementEventCount(wakeup_device_path_); | 
 |   wakeup_source_identifier_->HandleResume(); | 
 |   EXPECT_TRUE(wakeup_source_identifier_->InputDeviceCausedLastWake()); | 
 | } | 
 |  | 
 | }  // namespace | 
 | }  // namespace system | 
 | }  // namespace power_manager |