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