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