1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "android-base/properties.h"
18
19 #include <unistd.h>
20
21 #include <gtest/gtest.h>
22
23 #include <atomic>
24 #include <chrono>
25 #include <string>
26 #include <thread>
27
28 #if !defined(_WIN32)
29 using namespace std::literals;
30 #endif
31
TEST(properties,smoke)32 TEST(properties, smoke) {
33 android::base::SetProperty("debug.libbase.property_test", "hello");
34
35 std::string s = android::base::GetProperty("debug.libbase.property_test", "");
36 ASSERT_EQ("hello", s);
37
38 android::base::SetProperty("debug.libbase.property_test", "world");
39 s = android::base::GetProperty("debug.libbase.property_test", "");
40 ASSERT_EQ("world", s);
41
42 s = android::base::GetProperty("this.property.does.not.exist", "");
43 ASSERT_EQ("", s);
44
45 s = android::base::GetProperty("this.property.does.not.exist", "default");
46 ASSERT_EQ("default", s);
47 }
48
TEST(properties,too_long)49 TEST(properties, too_long) {
50 #if !defined(_WIN32)
51 if (getuid() != 0) {
52 GTEST_SKIP() << "Skipping test, must be run as root.";
53 }
54 #endif
55 // Properties have a fixed limit on the size of their value.
56 std::string key("debug.libbase.property_too_long");
57 std::string value(92, 'a');
58 ASSERT_FALSE(android::base::SetProperty(key, value));
59 ASSERT_EQ("missing", android::base::GetProperty(key, "missing"));
60
61 // Except for "ro." properties, which can have arbitrarily-long values.
62 key = "ro." + key + std::to_string(time(nullptr));
63 ASSERT_TRUE(android::base::SetProperty(key, value));
64 ASSERT_EQ(value, android::base::GetProperty(key, "missing"));
65 // ...because you can't change them.
66 ASSERT_FALSE(android::base::SetProperty(key, "hello"));
67 ASSERT_EQ(value, android::base::GetProperty(key, "missing"));
68 }
69
TEST(properties,empty_key)70 TEST(properties, empty_key) {
71 ASSERT_FALSE(android::base::SetProperty("", "hello"));
72 ASSERT_EQ("default", android::base::GetProperty("", "default"));
73 }
74
TEST(properties,empty_value)75 TEST(properties, empty_value) {
76 // Because you can't delete a property, people "delete" them by
77 // setting them to the empty string. In that case we'd want to
78 // keep the default value (like cutils' property_get did).
79 ASSERT_TRUE(android::base::SetProperty("debug.libbase.property_empty_value", ""));
80 ASSERT_EQ("default", android::base::GetProperty("debug.libbase.property_empty_value", "default"));
81 }
82
CheckGetBoolProperty(bool expected,const std::string & value,bool default_value)83 static void CheckGetBoolProperty(bool expected, const std::string& value, bool default_value) {
84 android::base::SetProperty("debug.libbase.property_test", value.c_str());
85 ASSERT_EQ(expected, android::base::GetBoolProperty("debug.libbase.property_test", default_value));
86 }
87
TEST(properties,GetBoolProperty_true)88 TEST(properties, GetBoolProperty_true) {
89 CheckGetBoolProperty(true, "1", false);
90 CheckGetBoolProperty(true, "y", false);
91 CheckGetBoolProperty(true, "yes", false);
92 CheckGetBoolProperty(true, "on", false);
93 CheckGetBoolProperty(true, "true", false);
94 }
95
TEST(properties,GetBoolProperty_false)96 TEST(properties, GetBoolProperty_false) {
97 CheckGetBoolProperty(false, "0", true);
98 CheckGetBoolProperty(false, "n", true);
99 CheckGetBoolProperty(false, "no", true);
100 CheckGetBoolProperty(false, "off", true);
101 CheckGetBoolProperty(false, "false", true);
102 }
103
TEST(properties,GetBoolProperty_default)104 TEST(properties, GetBoolProperty_default) {
105 CheckGetBoolProperty(true, "burp", true);
106 CheckGetBoolProperty(false, "burp", false);
107 }
108
CheckGetIntProperty()109 template <typename T> void CheckGetIntProperty() {
110 // Positive and negative.
111 android::base::SetProperty("debug.libbase.property_test", "-12");
112 EXPECT_EQ(T(-12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
113 android::base::SetProperty("debug.libbase.property_test", "12");
114 EXPECT_EQ(T(12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
115
116 // Default value.
117 android::base::SetProperty("debug.libbase.property_test", "");
118 EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
119
120 // Bounds checks.
121 android::base::SetProperty("debug.libbase.property_test", "0");
122 EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
123 android::base::SetProperty("debug.libbase.property_test", "1");
124 EXPECT_EQ(T(1), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
125 android::base::SetProperty("debug.libbase.property_test", "2");
126 EXPECT_EQ(T(2), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
127 android::base::SetProperty("debug.libbase.property_test", "3");
128 EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
129 }
130
CheckGetUintProperty()131 template <typename T> void CheckGetUintProperty() {
132 // Positive.
133 android::base::SetProperty("debug.libbase.property_test", "12");
134 EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
135
136 // Default value.
137 android::base::SetProperty("debug.libbase.property_test", "");
138 EXPECT_EQ(T(45), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
139
140 // Bounds checks.
141 android::base::SetProperty("debug.libbase.property_test", "12");
142 EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 33, 22));
143 android::base::SetProperty("debug.libbase.property_test", "12");
144 EXPECT_EQ(T(5), android::base::GetUintProperty<T>("debug.libbase.property_test", 5, 10));
145 }
146
TEST(properties,GetIntProperty_int8_t)147 TEST(properties, GetIntProperty_int8_t) { CheckGetIntProperty<int8_t>(); }
TEST(properties,GetIntProperty_int16_t)148 TEST(properties, GetIntProperty_int16_t) { CheckGetIntProperty<int16_t>(); }
TEST(properties,GetIntProperty_int32_t)149 TEST(properties, GetIntProperty_int32_t) { CheckGetIntProperty<int32_t>(); }
TEST(properties,GetIntProperty_int64_t)150 TEST(properties, GetIntProperty_int64_t) { CheckGetIntProperty<int64_t>(); }
151
TEST(properties,GetUintProperty_uint8_t)152 TEST(properties, GetUintProperty_uint8_t) { CheckGetUintProperty<uint8_t>(); }
TEST(properties,GetUintProperty_uint16_t)153 TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
TEST(properties,GetUintProperty_uint32_t)154 TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
TEST(properties,GetUintProperty_uint64_t)155 TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }
156
TEST(properties,WaitForProperty)157 TEST(properties, WaitForProperty) {
158 #if defined(__BIONIC__)
159 std::atomic<bool> flag{false};
160 std::thread thread([&]() {
161 std::this_thread::sleep_for(100ms);
162 android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
163 while (!flag) std::this_thread::yield();
164 android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
165 });
166
167 ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
168 flag = true;
169 ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", 1s));
170 thread.join();
171 #else
172 GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
173 #endif
174 }
175
TEST(properties,WaitForProperty_timeout)176 TEST(properties, WaitForProperty_timeout) {
177 #if defined(__BIONIC__)
178 auto t0 = std::chrono::steady_clock::now();
179 ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_timeout_test", "a",
180 200ms));
181 auto t1 = std::chrono::steady_clock::now();
182
183 ASSERT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 200ms);
184 // Upper bounds on timing are inherently flaky, but let's try...
185 ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
186 #else
187 GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
188 #endif
189 }
190
TEST(properties,WaitForProperty_MaxTimeout)191 TEST(properties, WaitForProperty_MaxTimeout) {
192 #if defined(__BIONIC__)
193 std::atomic<bool> flag{false};
194 std::thread thread([&]() {
195 android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
196 while (!flag) std::this_thread::yield();
197 std::this_thread::sleep_for(500ms);
198 android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
199 });
200
201 ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
202 flag = true;
203 // Test that this does not immediately return false due to overflow issues with the timeout.
204 ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b"));
205 thread.join();
206 #else
207 GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
208 #endif
209 }
210
TEST(properties,WaitForProperty_NegativeTimeout)211 TEST(properties, WaitForProperty_NegativeTimeout) {
212 #if defined(__BIONIC__)
213 std::atomic<bool> flag{false};
214 std::thread thread([&]() {
215 android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
216 while (!flag) std::this_thread::yield();
217 std::this_thread::sleep_for(500ms);
218 android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
219 });
220
221 ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
222 flag = true;
223 // Assert that this immediately returns with a negative timeout
224 ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", -100ms));
225 thread.join();
226 #else
227 GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
228 #endif
229 }
230
TEST(properties,WaitForPropertyCreation)231 TEST(properties, WaitForPropertyCreation) {
232 #if defined(__BIONIC__)
233 std::thread thread([&]() {
234 std::this_thread::sleep_for(100ms);
235 android::base::SetProperty("debug.libbase.WaitForPropertyCreation_test", "a");
236 });
237
238 ASSERT_TRUE(android::base::WaitForPropertyCreation(
239 "debug.libbase.WaitForPropertyCreation_test", 1s));
240 thread.join();
241 #else
242 GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
243 #endif
244 }
245
TEST(properties,WaitForPropertyCreation_timeout)246 TEST(properties, WaitForPropertyCreation_timeout) {
247 #if defined(__BIONIC__)
248 auto t0 = std::chrono::steady_clock::now();
249 ASSERT_FALSE(android::base::WaitForPropertyCreation(
250 "debug.libbase.WaitForPropertyCreation_timeout_test", 200ms));
251 auto t1 = std::chrono::steady_clock::now();
252
253 ASSERT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 200ms);
254 // Upper bounds on timing are inherently flaky, but let's try...
255 ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
256 #else
257 GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
258 #endif
259 }
260
TEST(properties,CachedProperty)261 TEST(properties, CachedProperty) {
262 #if defined(__BIONIC__)
263 android::base::CachedProperty cached_property("debug.libbase.CachedProperty_test");
264 bool changed;
265 cached_property.Get(&changed);
266
267 android::base::SetProperty("debug.libbase.CachedProperty_test", "foo");
268 ASSERT_STREQ("foo", cached_property.Get(&changed));
269 ASSERT_TRUE(changed);
270
271 ASSERT_STREQ("foo", cached_property.Get(&changed));
272 ASSERT_FALSE(changed);
273
274 android::base::SetProperty("debug.libbase.CachedProperty_test", "bar");
275 ASSERT_STREQ("bar", cached_property.Get(&changed));
276 ASSERT_TRUE(changed);
277
278 ASSERT_STREQ("bar", cached_property.Get(&changed));
279 ASSERT_FALSE(changed);
280
281 #else
282 GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
283 #endif
284 }
285