/* * Copyright (C) 2011 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 "base/flags.h" #include #include "android-base/properties.h" #include "common_runtime_test.h" namespace art { // Tests may be run in parallel so this helper class ensures // that we generate a unique test flag each time to avoid // tests stepping on each other class TestFlag { public: // Takes control of the tmp_file pointer. TestFlag(ScratchFile* tmp_file, FlagType flag_type) { tmp_file_.reset(tmp_file); std::string tmp_name = tmp_file_->GetFilename(); size_t tmp_last_slash = tmp_name.rfind('/'); tmp_name = tmp_name.substr(tmp_last_slash + 1); flag_name_ = "art.gtest." + tmp_name; system_prop_name_ = "dalvik.vm." + flag_name_; server_name_ = "persist.device_config.runtime_native." + flag_name_; cmd_line_name_ = flag_name_; std::replace(cmd_line_name_.begin(), cmd_line_name_.end(), '.', '-'); flag_.reset(new Flag(flag_name_, /*default_value=*/ 42, flag_type)); } void AssertCmdlineValue(bool has_value, int expected) { ASSERT_EQ(flag_->from_command_line_.has_value(), has_value); if (has_value) { ASSERT_EQ(flag_->from_command_line_.value(), expected); } } void AssertSysPropValue(bool has_value, int expected) { ASSERT_EQ(flag_->from_system_property_.has_value(), has_value); if (has_value) { ASSERT_EQ(flag_->from_system_property_.value(), expected); } } void AssertServerSettingValue(bool has_value, int expected) { ASSERT_EQ(flag_->from_server_setting_.has_value(), has_value); if (has_value) { ASSERT_EQ(flag_->from_server_setting_.value(), expected); } } void AssertDefaultValue(int expected) { ASSERT_EQ(flag_->default_, expected); } int Value() { return (*flag_)(); } std::string SystemProperty() const { return system_prop_name_; } std::string ServerSetting() const { return server_name_; } std::string CmdLineName() const { return cmd_line_name_; } private: std::unique_ptr tmp_file_; std::unique_ptr> flag_; std::string flag_name_; std::string cmd_line_name_; std::string system_prop_name_; std::string server_name_; }; class FlagsTests : public CommonRuntimeTest { protected: // We need to initialize the flag after the ScratchDir is created // but before we configure the runtime options (so that we can get // the right name for the config). // // So we do it in SetUpRuntimeOptions. virtual void SetUpRuntimeOptions(RuntimeOptions* options) { test_flag_.reset(new TestFlag(new ScratchFile(), FlagType::kDeviceConfig)); CommonRuntimeTest::SetUpRuntimeOptions(options); } virtual void TearDown() { test_flag_ = nullptr; CommonRuntimeTest::TearDown(); } std::unique_ptr test_flag_; }; class FlagsTestsWithCmdLineBase : public FlagsTests { public: explicit FlagsTestsWithCmdLineBase(FlagType type) : flag_type_(type) { } protected: virtual void TearDown() { android::base::SetProperty(test_flag_->SystemProperty(), ""); android::base::SetProperty(test_flag_->ServerSetting(), ""); FlagsTests::TearDown(); } virtual void SetUpRuntimeOptions(RuntimeOptions* options) { test_flag_.reset(new TestFlag(new ScratchFile(), flag_type_)); std::string option = "-X" + test_flag_->CmdLineName() + ":1"; options->emplace_back(option.c_str(), nullptr); } FlagType flag_type_; }; class FlagsTestsWithCmdLine : public FlagsTestsWithCmdLineBase { public: FlagsTestsWithCmdLine() : FlagsTestsWithCmdLineBase(FlagType::kDeviceConfig) { } }; class FlagsTestsCmdLineOnly : public FlagsTestsWithCmdLineBase { public: FlagsTestsCmdLineOnly() : FlagsTestsWithCmdLineBase(FlagType::kCmdlineOnly) { } }; // Validate that when no flag is set, the default is taken and none of the other // locations are populated TEST_F(FlagsTests, ValidateDefaultValue) { FlagBase::ReloadAllFlags("test"); test_flag_->AssertCmdlineValue(false, 1); test_flag_->AssertSysPropValue(false, 2); test_flag_->AssertServerSettingValue(false, 3); test_flag_->AssertDefaultValue(42); ASSERT_EQ(test_flag_->Value(), 42); } // Validate that the server side config is picked when it is set. TEST_F(FlagsTestsWithCmdLine, FlagsTestsGetValueServerSetting) { // On older releases (e.g. nougat) the system properties have very strict // limitations (e.g. for length) and setting the properties will fail. // On modern platforms this should not be the case, so condition the test // based on the success of setting the properties. if (!android::base::SetProperty(test_flag_->SystemProperty(), "2")) { LOG(ERROR) << "Release does not support property setting, skipping test: " << test_flag_->SystemProperty(); return; } if (android::base::SetProperty(test_flag_->ServerSetting(), "3")) { LOG(ERROR) << "Release does not support property setting, skipping test: " << test_flag_->ServerSetting(); return; } FlagBase::ReloadAllFlags("test"); test_flag_->AssertCmdlineValue(true, 1); test_flag_->AssertSysPropValue(true, 2); test_flag_->AssertServerSettingValue(true, 3); test_flag_->AssertDefaultValue(42); ASSERT_EQ(test_flag_->Value(), 3); } // Validate that the system property value is picked when the server one is not set. TEST_F(FlagsTestsWithCmdLine, FlagsTestsGetValueSysProperty) { if (!android::base::SetProperty(test_flag_->SystemProperty(), "2")) { LOG(ERROR) << "Release does not support property setting, skipping test: " << test_flag_->SystemProperty(); return; } FlagBase::ReloadAllFlags("test"); test_flag_->AssertCmdlineValue(true, 1); test_flag_->AssertSysPropValue(true, 2); test_flag_->AssertServerSettingValue(false, 3); test_flag_->AssertDefaultValue(42); ASSERT_EQ(test_flag_->Value(), 2); } // Validate that the cmdline value is picked when no properties are set. TEST_F(FlagsTestsWithCmdLine, FlagsTestsGetValueCmdline) { FlagBase::ReloadAllFlags("test"); test_flag_->AssertCmdlineValue(true, 1); test_flag_->AssertSysPropValue(false, 2); test_flag_->AssertServerSettingValue(false, 3); test_flag_->AssertDefaultValue(42); ASSERT_EQ(test_flag_->Value(), 1); } // Validate that cmdline only flags don't read system properties. TEST_F(FlagsTestsCmdLineOnly, CmdlineOnlyFlags) { if (!android::base::SetProperty(test_flag_->SystemProperty(), "2")) { LOG(ERROR) << "Release does not support property setting, skipping test: " << test_flag_->SystemProperty(); return; } if (android::base::SetProperty(test_flag_->ServerSetting(), "3")) { LOG(ERROR) << "Release does not support property setting, skipping test: " << test_flag_->ServerSetting(); return; } FlagBase::ReloadAllFlags("test"); test_flag_->AssertCmdlineValue(true, 1); test_flag_->AssertSysPropValue(false, 2); test_flag_->AssertServerSettingValue(false, 3); test_flag_->AssertDefaultValue(42); ASSERT_EQ(test_flag_->Value(), 1); } } // namespace art