1 /*
2 * Copyright (C) 2017 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 "persistent_properties.h"
18
19 #include <errno.h>
20
21 #include <vector>
22
23 #include <android-base/test_utils.h>
24 #include <gtest/gtest.h>
25
26 #include "util.h"
27
28 using namespace std::string_literals;
29
30 namespace android {
31 namespace init {
32
VectorToPersistentProperties(const std::vector<std::pair<std::string,std::string>> & input_properties)33 PersistentProperties VectorToPersistentProperties(
34 const std::vector<std::pair<std::string, std::string>>& input_properties) {
35 PersistentProperties persistent_properties;
36
37 for (const auto& [name, value] : input_properties) {
38 auto persistent_property_record = persistent_properties.add_properties();
39 persistent_property_record->set_name(name);
40 persistent_property_record->set_value(value);
41 }
42
43 return persistent_properties;
44 }
45
CheckPropertiesEqual(std::vector<std::pair<std::string,std::string>> expected,const PersistentProperties & persistent_properties)46 void CheckPropertiesEqual(std::vector<std::pair<std::string, std::string>> expected,
47 const PersistentProperties& persistent_properties) {
48 for (const auto& persistent_property_record : persistent_properties.properties()) {
49 auto it = std::find_if(expected.begin(), expected.end(),
50 [persistent_property_record](const auto& entry) {
51 return entry.first == persistent_property_record.name() &&
52 entry.second == persistent_property_record.value();
53 });
54 ASSERT_TRUE(it != expected.end())
55 << "Found unexpected property (" << persistent_property_record.name() << ", "
56 << persistent_property_record.value() << ")";
57 expected.erase(it);
58 }
59 auto joiner = [](const std::vector<std::pair<std::string, std::string>>& vector) {
60 std::string result;
61 for (const auto& [name, value] : vector) {
62 result += " (" + name + ", " + value + ")";
63 }
64 return result;
65 };
66 EXPECT_TRUE(expected.empty()) << "Did not find expected properties:" << joiner(expected);
67 }
68
TEST(persistent_properties,EndToEnd)69 TEST(persistent_properties, EndToEnd) {
70 TemporaryFile tf;
71 ASSERT_TRUE(tf.fd != -1);
72 persistent_property_filename = tf.path;
73
74 std::vector<std::pair<std::string, std::string>> persistent_properties = {
75 {"persist.sys.locale", "en-US"},
76 {"persist.sys.timezone", "America/Los_Angeles"},
77 {"persist.test.empty.value", ""},
78 {"persist.test.new.line", "abc\n\n\nabc"},
79 {"persist.test.numbers", "1234567890"},
80 {"persist.test.non.ascii", "\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F"},
81 // We don't currently allow for non-ascii names for system properties, but this is a policy
82 // decision, not a technical limitation.
83 {"persist.\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F", "non-ascii-name"},
84 };
85
86 ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
87
88 auto read_back_properties = LoadPersistentProperties();
89 CheckPropertiesEqual(persistent_properties, read_back_properties);
90 }
91
TEST(persistent_properties,AddProperty)92 TEST(persistent_properties, AddProperty) {
93 TemporaryFile tf;
94 ASSERT_TRUE(tf.fd != -1);
95 persistent_property_filename = tf.path;
96
97 std::vector<std::pair<std::string, std::string>> persistent_properties = {
98 {"persist.sys.timezone", "America/Los_Angeles"},
99 };
100 ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
101
102 WritePersistentProperty("persist.sys.locale", "pt-BR");
103
104 std::vector<std::pair<std::string, std::string>> persistent_properties_expected = {
105 {"persist.sys.timezone", "America/Los_Angeles"},
106 {"persist.sys.locale", "pt-BR"},
107 };
108
109 auto read_back_properties = LoadPersistentProperties();
110 CheckPropertiesEqual(persistent_properties_expected, read_back_properties);
111 }
112
TEST(persistent_properties,UpdateProperty)113 TEST(persistent_properties, UpdateProperty) {
114 TemporaryFile tf;
115 ASSERT_TRUE(tf.fd != -1);
116 persistent_property_filename = tf.path;
117
118 std::vector<std::pair<std::string, std::string>> persistent_properties = {
119 {"persist.sys.locale", "en-US"},
120 {"persist.sys.timezone", "America/Los_Angeles"},
121 };
122 ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
123
124 WritePersistentProperty("persist.sys.locale", "pt-BR");
125
126 std::vector<std::pair<std::string, std::string>> persistent_properties_expected = {
127 {"persist.sys.locale", "pt-BR"},
128 {"persist.sys.timezone", "America/Los_Angeles"},
129 };
130
131 auto read_back_properties = LoadPersistentProperties();
132 CheckPropertiesEqual(persistent_properties_expected, read_back_properties);
133 }
134
TEST(persistent_properties,UpdatePropertyBadParse)135 TEST(persistent_properties, UpdatePropertyBadParse) {
136 TemporaryFile tf;
137 ASSERT_TRUE(tf.fd != -1);
138 persistent_property_filename = tf.path;
139
140 ASSERT_TRUE(WriteFile(tf.path, "ab"));
141
142 WritePersistentProperty("persist.sys.locale", "pt-BR");
143
144 auto read_back_properties = LoadPersistentProperties();
145 EXPECT_GT(read_back_properties.properties().size(), 0);
146
147 auto it =
148 std::find_if(read_back_properties.properties().begin(),
149 read_back_properties.properties().end(), [](const auto& entry) {
150 return entry.name() == "persist.sys.locale" && entry.value() == "pt-BR";
151 });
152 EXPECT_FALSE(it == read_back_properties.properties().end());
153 }
154
155 } // namespace init
156 } // namespace android
157