github.com/stolowski/snapd@v0.0.0-20210407085831-115137ce5a22/osutil/disks/mockdisk_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package disks_test 21 22 import ( 23 "fmt" 24 25 . "gopkg.in/check.v1" 26 27 "github.com/snapcore/snapd/dirs" 28 "github.com/snapcore/snapd/osutil/disks" 29 "github.com/snapcore/snapd/testutil" 30 ) 31 32 type mockDiskSuite struct { 33 testutil.BaseTest 34 } 35 36 var _ = Suite(&mockDiskSuite{}) 37 38 func (s *mockDiskSuite) SetUpTest(c *C) { 39 dirs.SetRootDir(c.MkDir()) 40 } 41 42 func (s *mockDiskSuite) TestMockDeviceNameDisksToPartitionMapping(c *C) { 43 // one disk with different device names 44 d1 := &disks.MockDiskMapping{ 45 FilesystemLabelToPartUUID: map[string]string{ 46 "label1": "part1", 47 }, 48 DiskHasPartitions: true, 49 DevNum: "d1", 50 } 51 52 d2 := &disks.MockDiskMapping{ 53 FilesystemLabelToPartUUID: map[string]string{ 54 "label2": "part2", 55 }, 56 DiskHasPartitions: true, 57 DevNum: "d2", 58 } 59 60 m := map[string]*disks.MockDiskMapping{ 61 "devName1": d1, 62 "devName2": d1, 63 "other-disk": d2, 64 } 65 66 r := disks.MockDeviceNameDisksToPartitionMapping(m) 67 defer r() 68 69 res, err := disks.DiskFromDeviceName("devName1") 70 c.Assert(err, IsNil) 71 c.Assert(res, DeepEquals, d1) 72 73 res2, err := disks.DiskFromDeviceName("devName2") 74 c.Assert(err, IsNil) 75 c.Assert(res2, DeepEquals, d1) 76 77 _, err = disks.DiskFromDeviceName("devName3") 78 c.Assert(err, ErrorMatches, fmt.Sprintf("device name %q not mocked", "devName3")) 79 80 res3, err := disks.DiskFromDeviceName("other-disk") 81 c.Assert(err, IsNil) 82 c.Assert(res3, DeepEquals, d2) 83 } 84 85 func (s *mockDiskSuite) TestMockMountPointDisksToPartitionMappingVerifiesUniqueness(c *C) { 86 // two different disks with different DevNum's 87 d1 := &disks.MockDiskMapping{ 88 FilesystemLabelToPartUUID: map[string]string{ 89 "label1": "part1", 90 }, 91 DiskHasPartitions: true, 92 DevNum: "d1", 93 } 94 95 d2 := &disks.MockDiskMapping{ 96 FilesystemLabelToPartUUID: map[string]string{ 97 "label1": "part1", 98 }, 99 DiskHasPartitions: false, 100 DevNum: "d2", 101 } 102 103 // the pointers are different, and they are not the same 104 c.Assert(d1, Not(Equals), d2) 105 c.Assert(d1, Not(DeepEquals), d2) 106 107 m := map[disks.Mountpoint]*disks.MockDiskMapping{ 108 {Mountpoint: "mount1"}: d1, 109 {Mountpoint: "mount2"}: d1, 110 {Mountpoint: "mount3"}: d2, 111 } 112 113 // mocking works 114 r := disks.MockMountPointDisksToPartitionMapping(m) 115 defer r() 116 117 // changing so they have the same DevNum doesn't work though 118 d2.DevNum = "d1" 119 c.Assert( 120 func() { disks.MockMountPointDisksToPartitionMapping(m) }, 121 PanicMatches, 122 `mocked disks .* and .* have the same DevNum \(d1\) but are not the same object`, 123 ) 124 125 // mocking with just one disk at multiple mount points works too 126 m2 := map[disks.Mountpoint]*disks.MockDiskMapping{ 127 {Mountpoint: "mount1"}: d1, 128 {Mountpoint: "mount2"}: d1, 129 } 130 r = disks.MockMountPointDisksToPartitionMapping(m2) 131 defer r() 132 } 133 134 func (s *mockDiskSuite) TestMockMountPointDisksToPartitionMappingVerifiesConsistency(c *C) { 135 d1 := &disks.MockDiskMapping{ 136 FilesystemLabelToPartUUID: map[string]string{ 137 "label1": "part1", 138 }, 139 DiskHasPartitions: true, 140 DevNum: "d1", 141 } 142 143 // a mountpoint mapping where the same mountpoint has different options for 144 // the source mountpoint 145 m := map[disks.Mountpoint]*disks.MockDiskMapping{ 146 {Mountpoint: "mount1", IsDecryptedDevice: false}: d1, 147 {Mountpoint: "mount1", IsDecryptedDevice: true}: d1, 148 } 149 150 // mocking shouldn't work 151 c.Assert( 152 func() { disks.MockMountPointDisksToPartitionMapping(m) }, 153 PanicMatches, 154 // use .* for true/false since iterating over map order is not defined 155 `mocked source mountpoint mount1 is duplicated with different options - previous option for IsDecryptedDevice was .*, current option is .*`, 156 ) 157 } 158 159 func (s *mockDiskSuite) TestMockMountPointDisksToPartitionMapping(c *C) { 160 d1 := &disks.MockDiskMapping{ 161 FilesystemLabelToPartUUID: map[string]string{ 162 "label1": "part1", 163 }, 164 PartitionLabelToPartUUID: map[string]string{ 165 "part-label1": "part1", 166 }, 167 DiskHasPartitions: true, 168 DevNum: "d1", 169 } 170 171 d2 := &disks.MockDiskMapping{ 172 FilesystemLabelToPartUUID: map[string]string{ 173 "label2": "part2", 174 }, 175 PartitionLabelToPartUUID: map[string]string{ 176 "part-label2": "part2", 177 }, 178 DiskHasPartitions: true, 179 DevNum: "d2", 180 } 181 182 r := disks.MockMountPointDisksToPartitionMapping( 183 map[disks.Mountpoint]*disks.MockDiskMapping{ 184 {Mountpoint: "mount1"}: d1, 185 {Mountpoint: "mount2"}: d1, 186 {Mountpoint: "mount3"}: d2, 187 }, 188 ) 189 defer r() 190 191 // we can find the mock disk 192 foundDisk, err := disks.DiskFromMountPoint("mount1", nil) 193 c.Assert(err, IsNil) 194 195 // and it has filesystem labels 196 uuid, err := foundDisk.FindMatchingPartitionUUIDWithFsLabel("label1") 197 c.Assert(err, IsNil) 198 c.Assert(uuid, Equals, "part1") 199 200 // and partition labels 201 uuid, err = foundDisk.FindMatchingPartitionUUIDWithPartLabel("part-label1") 202 c.Assert(err, IsNil) 203 c.Assert(uuid, Equals, "part1") 204 205 // the same mount point is always from the same disk 206 matches, err := foundDisk.MountPointIsFromDisk("mount1", nil) 207 c.Assert(err, IsNil) 208 c.Assert(matches, Equals, true) 209 210 // mount2 goes to the same disk, as per the mapping above 211 matches, err = foundDisk.MountPointIsFromDisk("mount2", nil) 212 c.Assert(err, IsNil) 213 c.Assert(matches, Equals, true) 214 215 // mount3 does not however 216 matches, err = foundDisk.MountPointIsFromDisk("mount3", nil) 217 c.Assert(err, IsNil) 218 c.Assert(matches, Equals, false) 219 220 // a disk from mount3 is also able to be found 221 foundDisk2, err := disks.DiskFromMountPoint("mount3", nil) 222 c.Assert(err, IsNil) 223 224 // we can find label2 from mount3's disk 225 uuid, err = foundDisk2.FindMatchingPartitionUUIDWithFsLabel("label2") 226 c.Assert(err, IsNil) 227 c.Assert(uuid, Equals, "part2") 228 229 // and the partition label 230 uuid, err = foundDisk2.FindMatchingPartitionUUIDWithPartLabel("part-label2") 231 c.Assert(err, IsNil) 232 c.Assert(uuid, Equals, "part2") 233 234 // we can't find label1 from mount1's or mount2's disk 235 _, err = foundDisk2.FindMatchingPartitionUUIDWithFsLabel("label1") 236 c.Assert(err, ErrorMatches, "filesystem label \"label1\" not found") 237 c.Assert(err, DeepEquals, disks.PartitionNotFoundError{ 238 SearchType: "filesystem-label", 239 SearchQuery: "label1", 240 }) 241 242 _, err = foundDisk2.FindMatchingPartitionUUIDWithPartLabel("part-label1") 243 c.Assert(err, ErrorMatches, "partition label \"part-label1\" not found") 244 c.Assert(err, DeepEquals, disks.PartitionNotFoundError{ 245 SearchType: "partition-label", 246 SearchQuery: "part-label1", 247 }) 248 249 // mount1 and mount2 do not match mount3 disk 250 matches, err = foundDisk2.MountPointIsFromDisk("mount1", nil) 251 c.Assert(err, IsNil) 252 c.Assert(matches, Equals, false) 253 matches, err = foundDisk2.MountPointIsFromDisk("mount2", nil) 254 c.Assert(err, IsNil) 255 c.Assert(matches, Equals, false) 256 } 257 258 func (s *mockDiskSuite) TestMockMountPointDisksToPartitionMappingDecryptedDevices(c *C) { 259 d1 := &disks.MockDiskMapping{ 260 FilesystemLabelToPartUUID: map[string]string{ 261 "ubuntu-seed": "ubuntu-seed-part", 262 "ubuntu-boot": "ubuntu-boot-part", 263 "ubuntu-data-enc": "ubuntu-data-enc-part", 264 }, 265 DiskHasPartitions: true, 266 DevNum: "d1", 267 } 268 269 r := disks.MockMountPointDisksToPartitionMapping( 270 map[disks.Mountpoint]*disks.MockDiskMapping{ 271 {Mountpoint: "/run/mnt/ubuntu-boot"}: d1, 272 {Mountpoint: "/run/mnt/ubuntu-seed"}: d1, 273 { 274 Mountpoint: "/run/mnt/ubuntu-data", 275 IsDecryptedDevice: true, 276 }: d1, 277 }, 278 ) 279 defer r() 280 281 // first we get ubuntu-boot (which is not a decrypted device) 282 d, err := disks.DiskFromMountPoint("/run/mnt/ubuntu-boot", nil) 283 c.Assert(err, IsNil) 284 285 // next we find ubuntu-seed (also not decrypted) 286 label, err := d.FindMatchingPartitionUUIDWithFsLabel("ubuntu-seed") 287 c.Assert(err, IsNil) 288 c.Assert(label, Equals, "ubuntu-seed-part") 289 290 // then we find ubuntu-data-enc, which is not a decrypted device 291 label, err = d.FindMatchingPartitionUUIDWithFsLabel("ubuntu-data-enc") 292 c.Assert(err, IsNil) 293 c.Assert(label, Equals, "ubuntu-data-enc-part") 294 295 // and then finally ubuntu-data enc is from the same disk as ubuntu-boot 296 // with IsDecryptedDevice = true 297 opts := &disks.Options{IsDecryptedDevice: true} 298 matches, err := d.MountPointIsFromDisk("/run/mnt/ubuntu-data", opts) 299 c.Assert(err, IsNil) 300 c.Assert(matches, Equals, true) 301 }