1 /*
2 * Copyright 2020 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 "storage/legacy_config_file.h"
18
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21
22 #include <filesystem>
23
24 #include "os/files.h"
25 #include "storage/device.h"
26
27 namespace testing {
28
29 using bluetooth::os::ReadSmallFile;
30 using bluetooth::os::WriteToFile;
31 using bluetooth::storage::ConfigCache;
32 using bluetooth::storage::Device;
33 using bluetooth::storage::LegacyConfigFile;
34
TEST(LegacyConfigFileTest,write_and_read_loop_back_test)35 TEST(LegacyConfigFileTest, write_and_read_loop_back_test) {
36 auto temp_dir = std::filesystem::temp_directory_path();
37 auto temp_config = temp_dir / "temp_config.txt";
38
39 ConfigCache config(100, Device::kLinkKeyProperties);
40 config.SetProperty("A", "B", "C");
41 config.SetProperty("AA:BB:CC:DD:EE:FF", "B", "C");
42 config.SetProperty("AA:BB:CC:DD:EE:FF", "C", "D");
43 config.SetProperty("CC:DD:EE:FF:00:11", "LinkKey", "AABBAABBCCDDEE");
44 EXPECT_TRUE(config.HasProperty("CC:DD:EE:FF:00:11", "LinkKey"));
45 EXPECT_THAT(config.GetPersistentSections(), ElementsAre("CC:DD:EE:FF:00:11"));
46
47 EXPECT_TRUE(LegacyConfigFile::FromPath(temp_config.string()).Write(config));
48 auto config_read = LegacyConfigFile::FromPath(temp_config.string()).Read(100);
49 EXPECT_TRUE(config_read);
50 // Unpaired devices do not exist in persistent config file
51 config.RemoveSection("AA:BB:CC:DD:EE:FF");
52 EXPECT_EQ(config, *config_read);
53 EXPECT_THAT(config_read->GetPersistentSections(), ElementsAre("CC:DD:EE:FF:00:11"));
54 EXPECT_THAT(config_read->GetProperty("A", "B"), Optional(StrEq("C")));
55 EXPECT_THAT(config_read->GetProperty("CC:DD:EE:FF:00:11", "LinkKey"), Optional(StrEq("AABBAABBCCDDEE")));
56
57 EXPECT_TRUE(std::filesystem::remove(temp_config));
58 }
59
60 static const std::string kReadTestConfig =
61 "[Info]\n"
62 "FileSource = Empty\n"
63 "TimeCreated = 2020-05-20 01:20:56\n"
64 "\n"
65 "[Metrics]\n"
66 "Salt256Bit = 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\n"
67 "\n"
68 "[Adapter]\n"
69 "Address = 01:02:03:ab:cd:ef\n"
70 "LE_LOCAL_KEY_IRK = fedcba0987654321fedcba0987654321\n"
71 "LE_LOCAL_KEY_IR = fedcba0987654321fedcba0987654322\n"
72 "LE_LOCAL_KEY_DHK = fedcba0987654321fedcba0987654323\n"
73 "LE_LOCAL_KEY_ER = fedcba0987654321fedcba0987654324\n"
74 "ScanMode = 2\n"
75 "DiscoveryTimeout = 120\n"
76 "\n"
77 "[01:02:03:ab:cd:ea]\n"
78 "name = hello world\n"
79 "LinkKey = fedcba0987654321fedcba0987654328\n";
80
TEST(LegacyConfigFileTest,read_test)81 TEST(LegacyConfigFileTest, read_test) {
82 auto temp_dir = std::filesystem::temp_directory_path();
83 auto temp_config = temp_dir / "temp_config.txt";
84 EXPECT_TRUE(WriteToFile(temp_config.string(), kReadTestConfig));
85
86 auto config_read = LegacyConfigFile::FromPath(temp_config.string()).Read(100);
87 EXPECT_TRUE(config_read);
88 EXPECT_THAT(config_read->GetPersistentSections(), ElementsAre("01:02:03:ab:cd:ea"));
89 EXPECT_THAT(config_read->GetProperty("Info", "FileSource"), Optional(StrEq("Empty")));
90 EXPECT_THAT(config_read->GetProperty("Info", "FileSource"), Optional(StrEq("Empty")));
91 EXPECT_THAT(
92 config_read->GetProperty("01:02:03:ab:cd:ea", "LinkKey"), Optional(StrEq("fedcba0987654321fedcba0987654328")));
93
94 EXPECT_TRUE(std::filesystem::remove(temp_config));
95 }
96
97 static const std::string kWriteTestConfig =
98 "[Info]\n"
99 "FileSource = Empty\n"
100 "TimeCreated = \n"
101 "\n"
102 "[Adapter]\n"
103 "Address = 01:02:03:ab:cd:ef\n"
104 "\n"
105 "[01:02:03:ab:cd:ea]\n"
106 "name = hello world\n"
107 "LinkKey = fedcba0987654321fedcba0987654328\n"
108 "\n";
109
TEST(LegacyConfigFileTest,write_test)110 TEST(LegacyConfigFileTest, write_test) {
111 auto temp_dir = std::filesystem::temp_directory_path();
112 auto temp_config = temp_dir / "temp_config.txt";
113
114 ConfigCache config(100, Device::kLinkKeyProperties);
115 config.SetProperty("Info", "FileSource", "Empty");
116 config.SetProperty("Info", "TimeCreated", "");
117 config.SetProperty("Adapter", "Address", "01:02:03:ab:cd:ef");
118 config.SetProperty("01:02:03:ab:cd:ea", "name", "hello world");
119 config.SetProperty("01:02:03:ab:cd:ea", "LinkKey", "fedcba0987654321fedcba0987654328");
120 EXPECT_TRUE(LegacyConfigFile::FromPath(temp_config.string()).Write(config));
121
122 EXPECT_THAT(ReadSmallFile(temp_config.string()), Optional(StrEq(kWriteTestConfig)));
123
124 EXPECT_TRUE(std::filesystem::remove(temp_config));
125 }
126
127 static const std::string kConfigWithDuplicateSectionAndKey =
128 " \n\
129 first_key=value \n\
130 \n\
131 # Device ID (DID) configuration \n\
132 [DID] \n\
133 \n\
134 # Record Number: 1, 2 or 3 - maximum of 3 records \n\
135 recordNumber = 1 \n\
136 \n\
137 # Primary Record - true or false (default) \n\
138 # There can be only one primary record \n\
139 primaryRecord = true \n\
140 \n\
141 # Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device \n\
142 # 0x000F = Broadcom Corporation (default) \n\
143 #vendorId = 0x000F \n\
144 \n\
145 # Vendor ID Source \n\
146 # 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default) \n\
147 # 0x0002 = USB Implementer's Forum assigned Device ID Vendor ID value \n\
148 #vendorIdSource = 0x0001 \n\
149 \n\
150 # Product ID & Product Version \n\
151 # Per spec DID v1.3 0xJJMN for version is interpreted as JJ.M.N \n\
152 # JJ: major version number, M: minor version number, N: sub-minor version number \n\
153 # For example: 1200, v14.3.6 \n\
154 productId = 0x1200 \n\
155 version = 0x1111 \n\
156 \n\
157 # Optional attributes \n\
158 #clientExecutableURL = \n\
159 #serviceDescription = \n\
160 #documentationURL = \n\
161 \n\
162 # Additional optional DID records. Bluedroid supports up to 3 records. \n\
163 [DID] \n\
164 [DID] \n\
165 version = 0x1436 \n\
166 \n\
167 HiSyncId = 18446744073709551615 \n\
168 HiSyncId2 = 15001900 \n\
169 ";
170
TEST(LegacyConfigFileTest,duplicate_section_and_key_test)171 TEST(LegacyConfigFileTest, duplicate_section_and_key_test) {
172 auto temp_dir = std::filesystem::temp_directory_path();
173 auto temp_config = temp_dir / "temp_config.txt";
174 ASSERT_TRUE(WriteToFile(temp_config.string(), kConfigWithDuplicateSectionAndKey));
175
176 auto config_read = LegacyConfigFile::FromPath(temp_config.string()).Read(100);
177 ASSERT_TRUE(config_read);
178 EXPECT_THAT(config_read->GetProperty(ConfigCache::kDefaultSectionName, "first_key"), Optional(StrEq("value")));
179 // All sections with the same name merge into the same key-value pair
180 EXPECT_THAT(config_read->GetProperty("DID", "primaryRecord"), Optional(StrEq("true")));
181 // When keys are repeated, the later one wins
182 EXPECT_THAT(config_read->GetProperty("DID", "version"), Optional(StrEq("0x1436")));
183
184 EXPECT_TRUE(std::filesystem::remove(temp_config));
185 }
186
187 } // namespace testing