blob: cc18bd9364fcd470328b67354a7be4651786e30f [file] [log] [blame]
// 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/suspend_configurator.h"
#include <stdint.h>
#include <string>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/strings/string_number_conversions.h>
#include <gtest/gtest.h>
#include "power_manager/common/fake_prefs.h"
#include "power_manager/common/power_constants.h"
namespace power_manager {
namespace system {
namespace {
// Path to write to configure system suspend mode.
static constexpr char kSuspendModePath[] = "/sys/power/mem_sleep";
// suspend to idle (S0iX) suspend mode
static constexpr char kSuspendModeFreeze[] = "s2idle";
// shallow/standby(S1) suspend mode
static constexpr char kSuspendModeShallow[] = "shallow";
// deep sleep(S3) suspend mode
static constexpr char kSuspendModeDeep[] = "deep";
static constexpr char kECLastResumeResultPath[] =
"/sys/kernel/debug/cros_ec/last_resume_result";
static constexpr char kECResumeResultHang[] = "0x80000001";
static constexpr char kECResumeResultNoHang[] = "0x7FFFFFFF";
// Creates an empty sysfs file rooted in |temp_root_dir|. For example if
// |temp_root_dir| is "/tmp/xxx" and |sys_path| is "/sys/power/temp", creates
// "/tmp/xxx/sys/power/temp" with all necessary root directories.
void CreateSysfsFileInTempRootDir(const base::FilePath& temp_root_dir,
const std::string& sys_path) {
base::FilePath path = temp_root_dir.Append(sys_path.substr(1));
ASSERT_TRUE(base::CreateDirectory(path.DirName()));
CHECK_EQ(base::WriteFile(path, "", 0), 0);
}
} // namespace
class SuspendConfiguratorTest : public ::testing::Test {
public:
SuspendConfiguratorTest() {
// Temporary directory mimicking a root directory.
CHECK(temp_root_dir_.CreateUniqueTempDir());
base::FilePath temp_root_dir_path = temp_root_dir_.GetPath();
suspend_configurator_.set_prefix_path_for_testing(temp_root_dir_path);
CreateSysfsFileInTempRootDir(
temp_root_dir_path, SuspendConfigurator::kConsoleSuspendPath.value());
CreateSysfsFileInTempRootDir(temp_root_dir_path, kSuspendModePath);
}
~SuspendConfiguratorTest() override = default;
protected:
// Returns |orig| rooted within the temporary root dir created for testing.
base::FilePath GetPath(const base::FilePath& orig) const {
return temp_root_dir_.GetPath().Append(orig.value().substr(1));
}
std::string ReadFile(const base::FilePath& file) {
std::string file_contents;
EXPECT_TRUE(base::ReadFileToString(file, &file_contents));
return file_contents;
}
base::ScopedTempDir temp_root_dir_;
FakePrefs prefs_;
SuspendConfigurator suspend_configurator_;
};
// Test console is enabled during supend to S3 by default.
TEST_F(SuspendConfiguratorTest, TestDefaultConsoleSuspendForS3) {
base::FilePath console_suspend_path =
GetPath(SuspendConfigurator::kConsoleSuspendPath);
prefs_.SetInt64(kSuspendToIdlePref, 0);
suspend_configurator_.Init(&prefs_);
// Make sure console is enabled if system suspends to S3.
EXPECT_EQ("N", ReadFile(console_suspend_path));
}
// Test console is disabled during supend to S0iX by default.
TEST_F(SuspendConfiguratorTest, TestDefaultConsoleSuspendForS0ix) {
base::FilePath console_suspend_path =
GetPath(SuspendConfigurator::kConsoleSuspendPath);
prefs_.SetInt64(kSuspendToIdlePref, 1);
suspend_configurator_.Init(&prefs_);
// Make sure console is disabled if S0ix is enabled.
EXPECT_EQ("Y", ReadFile(console_suspend_path));
}
// Test default value to suspend console is overwritten if
// |kEnableConsoleDuringSuspendPref| is set.
TEST_F(SuspendConfiguratorTest, TestDefaultConsoleSuspendOverwritten) {
base::FilePath console_suspend_path =
GetPath(SuspendConfigurator::kConsoleSuspendPath);
prefs_.SetInt64(kSuspendToIdlePref, 1);
prefs_.SetInt64(kEnableConsoleDuringSuspendPref, 1);
suspend_configurator_.Init(&prefs_);
// Make sure console is not disabled though the default is to disable it.
EXPECT_EQ("N", ReadFile(console_suspend_path));
}
// Test that suspend mode is set to |kSuspendModeFreeze| if suspend_to_idle is
// enabled.
TEST_F(SuspendConfiguratorTest, TestSuspendModeIdle) {
base::FilePath suspend_mode_path = GetPath(base::FilePath(kSuspendModePath));
// Suspend mode should be configured to |kSuspendModeFreeze| even when
// |kSuspendModePref| is configured to something else.
prefs_.SetInt64(kSuspendToIdlePref, 1);
prefs_.SetString(kSuspendModePref, kSuspendModeShallow);
suspend_configurator_.Init(&prefs_);
suspend_configurator_.PrepareForSuspend(base::TimeDelta());
EXPECT_EQ(kSuspendModeFreeze, ReadFile(suspend_mode_path));
}
// Test that suspend mode is set to |kSuspendModeShallow| if |kSuspendModePref|
// is set to same when s0ix is not enabled.
TEST_F(SuspendConfiguratorTest, TestSuspendModeShallow) {
base::FilePath suspend_mode_path = GetPath(base::FilePath(kSuspendModePath));
prefs_.SetInt64(kSuspendToIdlePref, 0);
prefs_.SetString(kSuspendModePref, kSuspendModeShallow);
suspend_configurator_.Init(&prefs_);
suspend_configurator_.PrepareForSuspend(base::TimeDelta());
EXPECT_EQ(kSuspendModeShallow, ReadFile(suspend_mode_path));
}
// Test that suspend mode is set to |kSuspendModeDeep| if |kSuspendModePref|
// is invalid .
TEST_F(SuspendConfiguratorTest, TestSuspendModeDeep) {
base::FilePath suspend_mode_path = GetPath(base::FilePath(kSuspendModePath));
prefs_.SetInt64(kSuspendToIdlePref, 0);
prefs_.SetString(kSuspendModePref, "Junk");
suspend_configurator_.Init(&prefs_);
suspend_configurator_.PrepareForSuspend(base::TimeDelta());
EXPECT_EQ(kSuspendModeDeep, ReadFile(suspend_mode_path));
}
// Test that UndoPrepareForSuspend() returns success when
// |kECLastResumeResultPath| does not exist .
TEST_F(SuspendConfiguratorTest, TestNokECLastResumeResultPath) {
EXPECT_TRUE(suspend_configurator_.UndoPrepareForSuspend());
}
// Test that UndoPrepareForSuspend() returns success/failure based on value in
// |kECLastResumeResultPath|.
TEST_F(SuspendConfiguratorTest, TestkECLastResumeResultPathExist) {
CreateSysfsFileInTempRootDir(temp_root_dir_.GetPath(),
kECLastResumeResultPath);
// Empty |kECLastResumeResultPath| file should not fail suspend.
EXPECT_TRUE(suspend_configurator_.UndoPrepareForSuspend());
// Write a value that indicates hang to |kECLastResumeResultPath| and test
// UndoPrepareForSuspend() returns false.
std::string last_resume_result_string = kECResumeResultHang;
ASSERT_EQ(base::WriteFile(GetPath(base::FilePath(kECLastResumeResultPath)),
last_resume_result_string.c_str(),
last_resume_result_string.length()),
last_resume_result_string.length());
EXPECT_FALSE(suspend_configurator_.UndoPrepareForSuspend());
// Write a value that does not indicate hang to |kECLastResumeResultPath| and
// test UndoPrepareForSuspend() returns true.
last_resume_result_string = kECResumeResultNoHang;
ASSERT_EQ(base::WriteFile(GetPath(base::FilePath(kECLastResumeResultPath)),
last_resume_result_string.c_str(),
last_resume_result_string.length()),
last_resume_result_string.length());
EXPECT_TRUE(suspend_configurator_.UndoPrepareForSuspend());
}
} // namespace system
} // namespace power_manager