1//
2// Copyright (C) 2012 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 "update_engine/common/prefs.h"
18
19#include <inttypes.h>
20
21#include <limits>
22#include <string>
23
24#include <base/files/file_util.h>
25#include <base/files/scoped_temp_dir.h>
26#include <base/macros.h>
27#include <base/strings/string_util.h>
28#include <base/strings/stringprintf.h>
29#include <gmock/gmock.h>
30#include <gtest/gtest.h>
31
32using std::string;
33using testing::Eq;
34using testing::_;
35
36namespace {
37// Test key used along the tests.
38const char kKey[] = "test-key";
39}
40
41namespace chromeos_update_engine {
42
43class PrefsTest : public ::testing::Test {
44 protected:
45  void SetUp() override {
46    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
47    prefs_dir_ = temp_dir_.path();
48    ASSERT_TRUE(prefs_.Init(prefs_dir_));
49  }
50
51  bool SetValue(const string& key, const string& value) {
52    return base::WriteFile(prefs_dir_.Append(key), value.data(),
53                           value.length()) == static_cast<int>(value.length());
54  }
55
56  base::ScopedTempDir temp_dir_;
57  base::FilePath prefs_dir_;
58  Prefs prefs_;
59};
60
61TEST_F(PrefsTest, GetFileNameForKey) {
62  const char kAllvalidCharsKey[] =
63      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-";
64  base::FilePath path;
65  EXPECT_TRUE(prefs_.file_storage_.GetFileNameForKey(kAllvalidCharsKey, &path));
66  EXPECT_EQ(prefs_dir_.Append(kAllvalidCharsKey).value(), path.value());
67}
68
69TEST_F(PrefsTest, GetFileNameForKeyBadCharacter) {
70  base::FilePath path;
71  EXPECT_FALSE(prefs_.file_storage_.GetFileNameForKey("ABC abc", &path));
72}
73
74TEST_F(PrefsTest, GetFileNameForKeyEmpty) {
75  base::FilePath path;
76  EXPECT_FALSE(prefs_.file_storage_.GetFileNameForKey("", &path));
77}
78
79TEST_F(PrefsTest, GetString) {
80  const string test_data = "test data";
81  ASSERT_TRUE(SetValue(kKey, test_data));
82  string value;
83  EXPECT_TRUE(prefs_.GetString(kKey, &value));
84  EXPECT_EQ(test_data, value);
85}
86
87TEST_F(PrefsTest, GetStringBadKey) {
88  string value;
89  EXPECT_FALSE(prefs_.GetString(",bad", &value));
90}
91
92TEST_F(PrefsTest, GetStringNonExistentKey) {
93  string value;
94  EXPECT_FALSE(prefs_.GetString("non-existent-key", &value));
95}
96
97TEST_F(PrefsTest, SetString) {
98  const char kValue[] = "some test value\non 2 lines";
99  EXPECT_TRUE(prefs_.SetString(kKey, kValue));
100  string value;
101  EXPECT_TRUE(base::ReadFileToString(prefs_dir_.Append(kKey), &value));
102  EXPECT_EQ(kValue, value);
103}
104
105TEST_F(PrefsTest, SetStringBadKey) {
106  const char kKeyWithDots[] = ".no-dots";
107  EXPECT_FALSE(prefs_.SetString(kKeyWithDots, "some value"));
108  EXPECT_FALSE(base::PathExists(prefs_dir_.Append(kKeyWithDots)));
109}
110
111TEST_F(PrefsTest, SetStringCreateDir) {
112  const char kValue[] = "test value";
113  base::FilePath subdir = prefs_dir_.Append("subdir1").Append("subdir2");
114  EXPECT_TRUE(prefs_.Init(subdir));
115  EXPECT_TRUE(prefs_.SetString(kKey, kValue));
116  string value;
117  EXPECT_TRUE(base::ReadFileToString(subdir.Append(kKey), &value));
118  EXPECT_EQ(kValue, value);
119}
120
121TEST_F(PrefsTest, SetStringDirCreationFailure) {
122  EXPECT_TRUE(prefs_.Init(base::FilePath("/dev/null")));
123  EXPECT_FALSE(prefs_.SetString(kKey, "test value"));
124}
125
126TEST_F(PrefsTest, SetStringFileCreationFailure) {
127  base::CreateDirectory(prefs_dir_.Append(kKey));
128  EXPECT_FALSE(prefs_.SetString(kKey, "test value"));
129  EXPECT_TRUE(base::DirectoryExists(prefs_dir_.Append(kKey)));
130}
131
132TEST_F(PrefsTest, GetInt64) {
133  ASSERT_TRUE(SetValue(kKey, " \n 25 \t "));
134  int64_t value;
135  EXPECT_TRUE(prefs_.GetInt64(kKey, &value));
136  EXPECT_EQ(25, value);
137}
138
139TEST_F(PrefsTest, GetInt64BadValue) {
140  ASSERT_TRUE(SetValue(kKey, "30a"));
141  int64_t value;
142  EXPECT_FALSE(prefs_.GetInt64(kKey, &value));
143}
144
145TEST_F(PrefsTest, GetInt64Max) {
146  ASSERT_TRUE(SetValue(kKey, base::StringPrintf(
147      "%" PRIi64, std::numeric_limits<int64_t>::max())));
148  int64_t value;
149  EXPECT_TRUE(prefs_.GetInt64(kKey, &value));
150  EXPECT_EQ(std::numeric_limits<int64_t>::max(), value);
151}
152
153TEST_F(PrefsTest, GetInt64Min) {
154  ASSERT_TRUE(SetValue(kKey, base::StringPrintf(
155        "%" PRIi64, std::numeric_limits<int64_t>::min())));
156  int64_t value;
157  EXPECT_TRUE(prefs_.GetInt64(kKey, &value));
158  EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
159}
160
161TEST_F(PrefsTest, GetInt64Negative) {
162  ASSERT_TRUE(SetValue(kKey, " \t -100 \n "));
163  int64_t value;
164  EXPECT_TRUE(prefs_.GetInt64(kKey, &value));
165  EXPECT_EQ(-100, value);
166}
167
168TEST_F(PrefsTest, GetInt64NonExistentKey) {
169  int64_t value;
170  EXPECT_FALSE(prefs_.GetInt64("random-key", &value));
171}
172
173TEST_F(PrefsTest, SetInt64) {
174  EXPECT_TRUE(prefs_.SetInt64(kKey, -123));
175  string value;
176  EXPECT_TRUE(base::ReadFileToString(prefs_dir_.Append(kKey), &value));
177  EXPECT_EQ("-123", value);
178}
179
180TEST_F(PrefsTest, SetInt64BadKey) {
181  const char kKeyWithSpaces[] = "s p a c e s";
182  EXPECT_FALSE(prefs_.SetInt64(kKeyWithSpaces, 20));
183  EXPECT_FALSE(base::PathExists(prefs_dir_.Append(kKeyWithSpaces)));
184}
185
186TEST_F(PrefsTest, SetInt64Max) {
187  EXPECT_TRUE(prefs_.SetInt64(kKey, std::numeric_limits<int64_t>::max()));
188  string value;
189  EXPECT_TRUE(base::ReadFileToString(prefs_dir_.Append(kKey), &value));
190  EXPECT_EQ(base::StringPrintf("%" PRIi64, std::numeric_limits<int64_t>::max()),
191            value);
192}
193
194TEST_F(PrefsTest, SetInt64Min) {
195  EXPECT_TRUE(prefs_.SetInt64(kKey, std::numeric_limits<int64_t>::min()));
196  string value;
197  EXPECT_TRUE(base::ReadFileToString(prefs_dir_.Append(kKey), &value));
198  EXPECT_EQ(base::StringPrintf("%" PRIi64, std::numeric_limits<int64_t>::min()),
199            value);
200}
201
202TEST_F(PrefsTest, GetBooleanFalse) {
203  ASSERT_TRUE(SetValue(kKey, " \n false \t "));
204  bool value;
205  EXPECT_TRUE(prefs_.GetBoolean(kKey, &value));
206  EXPECT_FALSE(value);
207}
208
209TEST_F(PrefsTest, GetBooleanTrue) {
210  const char kKey[] = "test-key";
211  ASSERT_TRUE(SetValue(kKey, " \t true \n "));
212  bool value;
213  EXPECT_TRUE(prefs_.GetBoolean(kKey, &value));
214  EXPECT_TRUE(value);
215}
216
217TEST_F(PrefsTest, GetBooleanBadValue) {
218  const char kKey[] = "test-key";
219  ASSERT_TRUE(SetValue(kKey, "1"));
220  bool value;
221  EXPECT_FALSE(prefs_.GetBoolean(kKey, &value));
222}
223
224TEST_F(PrefsTest, GetBooleanBadEmptyValue) {
225  const char kKey[] = "test-key";
226  ASSERT_TRUE(SetValue(kKey, ""));
227  bool value;
228  EXPECT_FALSE(prefs_.GetBoolean(kKey, &value));
229}
230
231TEST_F(PrefsTest, GetBooleanNonExistentKey) {
232  bool value;
233  EXPECT_FALSE(prefs_.GetBoolean("random-key", &value));
234}
235
236TEST_F(PrefsTest, SetBooleanTrue) {
237  const char kKey[] = "test-bool";
238  EXPECT_TRUE(prefs_.SetBoolean(kKey, true));
239  string value;
240  EXPECT_TRUE(base::ReadFileToString(prefs_dir_.Append(kKey), &value));
241  EXPECT_EQ("true", value);
242}
243
244TEST_F(PrefsTest, SetBooleanFalse) {
245  const char kKey[] = "test-bool";
246  EXPECT_TRUE(prefs_.SetBoolean(kKey, false));
247  string value;
248  EXPECT_TRUE(base::ReadFileToString(prefs_dir_.Append(kKey), &value));
249  EXPECT_EQ("false", value);
250}
251
252TEST_F(PrefsTest, SetBooleanBadKey) {
253  const char kKey[] = "s p a c e s";
254  EXPECT_FALSE(prefs_.SetBoolean(kKey, true));
255  EXPECT_FALSE(base::PathExists(prefs_dir_.Append(kKey)));
256}
257
258TEST_F(PrefsTest, ExistsWorks) {
259  // test that the key doesn't exist before we set it.
260  EXPECT_FALSE(prefs_.Exists(kKey));
261
262  // test that the key exists after we set it.
263  ASSERT_TRUE(prefs_.SetInt64(kKey, 8));
264  EXPECT_TRUE(prefs_.Exists(kKey));
265}
266
267TEST_F(PrefsTest, DeleteWorks) {
268  // test that it's alright to delete a non-existent key.
269  EXPECT_TRUE(prefs_.Delete(kKey));
270
271  // delete the key after we set it.
272  ASSERT_TRUE(prefs_.SetInt64(kKey, 0));
273  EXPECT_TRUE(prefs_.Delete(kKey));
274
275  // make sure it doesn't exist anymore.
276  EXPECT_FALSE(prefs_.Exists(kKey));
277}
278
279class MockPrefsObserver : public PrefsInterface::ObserverInterface {
280 public:
281  MOCK_METHOD1(OnPrefSet, void(const string&));
282  MOCK_METHOD1(OnPrefDeleted, void(const string& key));
283};
284
285TEST_F(PrefsTest, ObserversCalled) {
286  MockPrefsObserver mock_obserser;
287  prefs_.AddObserver(kKey, &mock_obserser);
288
289  EXPECT_CALL(mock_obserser, OnPrefSet(Eq(kKey)));
290  EXPECT_CALL(mock_obserser, OnPrefDeleted(_)).Times(0);
291  prefs_.SetString(kKey, "value");
292  testing::Mock::VerifyAndClearExpectations(&mock_obserser);
293
294  EXPECT_CALL(mock_obserser, OnPrefSet(_)).Times(0);
295  EXPECT_CALL(mock_obserser, OnPrefDeleted(Eq(kKey)));
296  prefs_.Delete(kKey);
297  testing::Mock::VerifyAndClearExpectations(&mock_obserser);
298
299  prefs_.RemoveObserver(kKey, &mock_obserser);
300}
301
302TEST_F(PrefsTest, OnlyCalledOnObservedKeys) {
303  MockPrefsObserver mock_obserser;
304  const char kUnusedKey[] = "unused-key";
305  prefs_.AddObserver(kUnusedKey, &mock_obserser);
306
307  EXPECT_CALL(mock_obserser, OnPrefSet(_)).Times(0);
308  EXPECT_CALL(mock_obserser, OnPrefDeleted(_)).Times(0);
309  prefs_.SetString(kKey, "value");
310  prefs_.Delete(kKey);
311
312  prefs_.RemoveObserver(kUnusedKey, &mock_obserser);
313}
314
315TEST_F(PrefsTest, RemovedObserversNotCalled) {
316  MockPrefsObserver mock_obserser_a, mock_obserser_b;
317  prefs_.AddObserver(kKey, &mock_obserser_a);
318  prefs_.AddObserver(kKey, &mock_obserser_b);
319  EXPECT_CALL(mock_obserser_a, OnPrefSet(_)).Times(2);
320  EXPECT_CALL(mock_obserser_b, OnPrefSet(_)).Times(1);
321  EXPECT_TRUE(prefs_.SetString(kKey, "value"));
322  prefs_.RemoveObserver(kKey, &mock_obserser_b);
323  EXPECT_TRUE(prefs_.SetString(kKey, "other value"));
324  prefs_.RemoveObserver(kKey, &mock_obserser_a);
325  EXPECT_TRUE(prefs_.SetString(kKey, "yet another value"));
326}
327
328TEST_F(PrefsTest, UnsuccessfulCallsNotObserved) {
329  MockPrefsObserver mock_obserser;
330  const char kInvalidKey[] = "no spaces or .";
331  prefs_.AddObserver(kInvalidKey, &mock_obserser);
332
333  EXPECT_CALL(mock_obserser, OnPrefSet(_)).Times(0);
334  EXPECT_CALL(mock_obserser, OnPrefDeleted(_)).Times(0);
335  EXPECT_FALSE(prefs_.SetString(kInvalidKey, "value"));
336  EXPECT_FALSE(prefs_.Delete(kInvalidKey));
337
338  prefs_.RemoveObserver(kInvalidKey, &mock_obserser);
339}
340
341class MemoryPrefsTest : public ::testing::Test {
342 protected:
343  MemoryPrefs prefs_;
344};
345
346TEST_F(MemoryPrefsTest, BasicTest) {
347  EXPECT_FALSE(prefs_.Exists(kKey));
348  int64_t value = 0;
349  EXPECT_FALSE(prefs_.GetInt64(kKey, &value));
350
351  EXPECT_TRUE(prefs_.SetInt64(kKey, 1234));
352  EXPECT_TRUE(prefs_.Exists(kKey));
353  EXPECT_TRUE(prefs_.GetInt64(kKey, &value));
354  EXPECT_EQ(1234, value);
355
356  EXPECT_TRUE(prefs_.Delete(kKey));
357  EXPECT_FALSE(prefs_.Exists(kKey));
358  EXPECT_FALSE(prefs_.Delete(kKey));
359}
360
361}  // namespace chromeos_update_engine
362