1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chromeos/disks/disk.h"
6 
7 #include <stdint.h>
8 
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "chromeos/dbus/cros_disks_client.h"
14 #include "dbus/message.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/cros_system_api/dbus/service_constants.h"
17 
18 namespace chromeos {
19 namespace disks {
20 namespace {
21 
22 const char kDevicePath[] = "/sys/device/path";
23 const char kDeviceFile[] = "/dev/sdb1";
24 const char kMountPath1[] = "/media/removable/UNTITLED";
25 const char kMountPath2[] = "/media/removable/second_mount_path";
26 const char kDriveModel[] = "DriveModel";
27 const char kIdLabel[] = "UNTITLED";
28 const char kIdUuid[] = "XXXX-YYYY";
29 const char kStorageDevicePath[] =
30     "/sys/devices/pci0000:00/0000:00:14.0/usb2/2-8/2-8:1.0/host14/target14:0:0/"
31     "14:0:0:0";
32 const char kProductId[] = "1234";
33 const char kProductName[] = "Product Name";
34 const char kVendorId[] = "0000";
35 const char kVendorName[] = "Vendor Name";
36 const char kFileSystemType[] = "exfat";
37 const uint64_t kDeviceSize = 16005464064;
38 const uint32_t kDeviceMediaType = cros_disks::DEVICE_MEDIA_SD;
39 
40 // Appends a boolean entry to a dictionary of type "a{sv}"
AppendBoolDictEntry(dbus::MessageWriter * array_writer,const std::string & key,bool value)41 void AppendBoolDictEntry(dbus::MessageWriter* array_writer,
42                          const std::string& key,
43                          bool value) {
44   dbus::MessageWriter entry_writer(nullptr);
45   array_writer->OpenDictEntry(&entry_writer);
46   entry_writer.AppendString(key);
47   entry_writer.AppendVariantOfBool(value);
48   array_writer->CloseContainer(&entry_writer);
49 }
50 
51 // Appends a string entry to a dictionary of type "a{sv}"
AppendStringDictEntry(dbus::MessageWriter * array_writer,const std::string & key,const std::string & value)52 void AppendStringDictEntry(dbus::MessageWriter* array_writer,
53                            const std::string& key,
54                            const std::string& value) {
55   dbus::MessageWriter entry_writer(nullptr);
56   array_writer->OpenDictEntry(&entry_writer);
57   entry_writer.AppendString(key);
58   entry_writer.AppendVariantOfString(value);
59   array_writer->CloseContainer(&entry_writer);
60 }
61 
62 // Appends a uint64 entry to a dictionary of type "a{sv}"
AppendUint64DictEntry(dbus::MessageWriter * array_writer,const std::string & key,uint64_t value)63 void AppendUint64DictEntry(dbus::MessageWriter* array_writer,
64                            const std::string& key,
65                            uint64_t value) {
66   dbus::MessageWriter entry_writer(nullptr);
67   array_writer->OpenDictEntry(&entry_writer);
68   entry_writer.AppendString(key);
69   entry_writer.AppendVariantOfUint64(value);
70   array_writer->CloseContainer(&entry_writer);
71 }
72 
73 // Appends a uint32 entry to a dictionary of type "a{sv}"
AppendUint32DictEntry(dbus::MessageWriter * array_writer,const std::string & key,uint64_t value)74 void AppendUint32DictEntry(dbus::MessageWriter* array_writer,
75                            const std::string& key,
76                            uint64_t value) {
77   dbus::MessageWriter entry_writer(nullptr);
78   array_writer->OpenDictEntry(&entry_writer);
79   entry_writer.AppendString(key);
80   entry_writer.AppendVariantOfUint32(value);
81   array_writer->CloseContainer(&entry_writer);
82 }
83 
AppendBasicProperties(dbus::MessageWriter * array_writer)84 void AppendBasicProperties(dbus::MessageWriter* array_writer) {
85   AppendStringDictEntry(array_writer, cros_disks::kDeviceFile, kDeviceFile);
86   AppendStringDictEntry(array_writer, cros_disks::kDriveModel, kDriveModel);
87   AppendStringDictEntry(array_writer, cros_disks::kIdLabel, kIdLabel);
88   AppendStringDictEntry(array_writer, cros_disks::kIdUuid, kIdUuid);
89   AppendStringDictEntry(array_writer, cros_disks::kStorageDevicePath,
90                         kStorageDevicePath);
91   AppendStringDictEntry(array_writer, cros_disks::kProductId, kProductId);
92   AppendStringDictEntry(array_writer, cros_disks::kProductName, kProductName);
93   AppendStringDictEntry(array_writer, cros_disks::kVendorId, kVendorId);
94   AppendStringDictEntry(array_writer, cros_disks::kVendorName, kVendorName);
95   AppendStringDictEntry(array_writer, cros_disks::kFileSystemType,
96                         kFileSystemType);
97   AppendUint64DictEntry(array_writer, cros_disks::kDeviceSize, kDeviceSize);
98   AppendUint32DictEntry(array_writer, cros_disks::kDeviceMediaType,
99                         kDeviceMediaType);
100 }
101 
102 // Builds a dbus reponse with a common set of fields.
BuildBasicDbusResponse()103 std::unique_ptr<dbus::Response> BuildBasicDbusResponse() {
104   std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
105   dbus::MessageWriter writer(response.get());
106   dbus::MessageWriter array_writer(nullptr);
107 
108   writer.OpenArray("{sv}", &array_writer);
109   AppendBasicProperties(&array_writer);
110   writer.CloseContainer(&array_writer);
111 
112   return response;
113 }
114 
TEST(DiskTest,ConstructFromDiskInfo)115 TEST(DiskTest, ConstructFromDiskInfo) {
116   const char kBaseMountpath[] = "/base/mount/path";
117 
118   std::unique_ptr<dbus::Response> response = BuildBasicDbusResponse();
119   DiskInfo disk_info(kDevicePath, response.get());
120   Disk disk(disk_info, false /* write_disabled_by_policy */, kBaseMountpath);
121 
122   EXPECT_EQ(kDevicePath, disk.device_path());
123   EXPECT_EQ(kDeviceFile, disk.file_path());
124   EXPECT_EQ(kIdLabel, disk.device_label());
125   EXPECT_EQ(kDriveModel, disk.drive_label());
126   EXPECT_EQ(kVendorId, disk.vendor_id());
127   EXPECT_EQ(kVendorName, disk.vendor_name());
128   EXPECT_EQ(kProductId, disk.product_id());
129   EXPECT_EQ(kProductName, disk.product_name());
130   EXPECT_EQ(kIdUuid, disk.fs_uuid());
131   EXPECT_EQ(kDeviceSize, disk.total_size_in_bytes());
132   EXPECT_EQ(DEVICE_TYPE_SD, disk.device_type());
133   EXPECT_EQ(kStorageDevicePath, disk.storage_device_path());
134   EXPECT_EQ(kBaseMountpath, disk.base_mount_path());
135   EXPECT_FALSE(disk.is_parent());
136   EXPECT_FALSE(disk.is_read_only());
137   EXPECT_FALSE(disk.is_read_only_hardware());
138   EXPECT_FALSE(disk.has_media());
139   EXPECT_FALSE(disk.on_boot_device());
140   EXPECT_FALSE(disk.on_removable_device());
141   EXPECT_FALSE(disk.is_mounted());
142   EXPECT_FALSE(disk.IsStatefulPartition());
143   EXPECT_FALSE(disk.is_auto_mountable());
144   EXPECT_TRUE(disk.is_first_mount());
145 
146   // Drives are hidden by default.
147   EXPECT_TRUE(disk.is_hidden());
148 }
149 
BuildDiskWithProperty(const std::string & property,bool value)150 std::unique_ptr<Disk> BuildDiskWithProperty(const std::string& property,
151                                             bool value) {
152   std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
153   {
154     dbus::MessageWriter writer(response.get());
155     dbus::MessageWriter array_writer(nullptr);
156 
157     writer.OpenArray("{sv}", &array_writer);
158     AppendBasicProperties(&array_writer);
159     AppendBoolDictEntry(&array_writer, property, value);
160     writer.CloseContainer(&array_writer);
161   }
162   DiskInfo disk_info(kDevicePath, response.get());
163   return std::make_unique<Disk>(disk_info, false, "");
164 }
165 
TEST(DiskTest,ConstructFromDiskInfo_BoolProperties)166 TEST(DiskTest, ConstructFromDiskInfo_BoolProperties) {
167   {
168     auto disk = BuildDiskWithProperty(cros_disks::kDeviceIsDrive, true);
169     EXPECT_TRUE(disk->is_parent());
170   }
171   {
172     auto disk = BuildDiskWithProperty(cros_disks::kDeviceIsReadOnly, true);
173     EXPECT_TRUE(disk->is_read_only());
174     EXPECT_TRUE(disk->is_read_only_hardware());
175   }
176   {
177     auto disk =
178         BuildDiskWithProperty(cros_disks::kDeviceIsMediaAvailable, true);
179     EXPECT_TRUE(disk->has_media());
180   }
181   {
182     auto disk = BuildDiskWithProperty(cros_disks::kDeviceIsOnBootDevice, true);
183     EXPECT_TRUE(disk->on_boot_device());
184   }
185   {
186     auto disk =
187         BuildDiskWithProperty(cros_disks::kDeviceIsOnRemovableDevice, true);
188     EXPECT_TRUE(disk->on_removable_device());
189   }
190   {
191     auto disk = BuildDiskWithProperty(cros_disks::kIsAutoMountable, true);
192     EXPECT_TRUE(disk->is_auto_mountable());
193   }
194 }
195 
TEST(DiskTest,ConstructFromDiskInfo_WriteDisabledByPolicy)196 TEST(DiskTest, ConstructFromDiskInfo_WriteDisabledByPolicy) {
197   std::unique_ptr<dbus::Response> response = BuildBasicDbusResponse();
198   DiskInfo disk_info(kDevicePath, response.get());
199   Disk disk(disk_info, true /* write_disabled_by_policy */, "");
200 
201   EXPECT_TRUE(disk.is_read_only());
202   EXPECT_FALSE(disk.is_read_only_hardware());
203 }
204 
TEST(DiskTest,ConstructFromDiskInfo_Mounted)205 TEST(DiskTest, ConstructFromDiskInfo_Mounted) {
206   std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
207   {
208     dbus::MessageWriter writer(response.get());
209     dbus::MessageWriter array_writer(nullptr);
210 
211     writer.OpenArray("{sv}", &array_writer);
212     AppendBasicProperties(&array_writer);
213     {
214       std::vector<std::string> mounted_paths = {kMountPath1, kMountPath2};
215 
216       dbus::MessageWriter entry_writer(nullptr);
217       array_writer.OpenDictEntry(&entry_writer);
218       entry_writer.AppendString(cros_disks::kDeviceMountPaths);
219       dbus::MessageWriter variant_writer(nullptr);
220       entry_writer.OpenVariant("as", &variant_writer);
221       variant_writer.AppendArrayOfStrings(mounted_paths);
222       entry_writer.CloseContainer(&variant_writer);
223       array_writer.CloseContainer(&entry_writer);
224     }
225     writer.CloseContainer(&array_writer);
226   }
227 
228   DiskInfo disk_info(kDevicePath, response.get());
229   Disk disk(disk_info, false, "");
230 
231   EXPECT_TRUE(disk.is_mounted());
232   EXPECT_EQ(kMountPath1, disk.mount_path());
233 }
234 
TEST(DiskTest,SetMountPath)235 TEST(DiskTest, SetMountPath) {
236   std::unique_ptr<dbus::Response> response = BuildBasicDbusResponse();
237   DiskInfo disk_info(kDevicePath, response.get());
238   Disk disk(disk_info, false /* write_disabled_by_policy */, "");
239 
240   EXPECT_EQ("", disk.mount_path());
241   EXPECT_EQ("", disk.base_mount_path());
242   EXPECT_FALSE(disk.is_mounted());
243 
244   disk.SetMountPath(kMountPath1);
245   EXPECT_EQ(kMountPath1, disk.mount_path());
246   EXPECT_EQ(kMountPath1, disk.base_mount_path());
247   EXPECT_FALSE(disk.is_mounted());
248 
249   disk.set_mounted(true);
250   EXPECT_TRUE(disk.is_mounted());
251 }
252 
253 }  // namespace
254 }  // namespace disks
255 }  // namespace chromeos
256