github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/mount/block/blockdev_test.go (about) 1 // Copyright 2017-2021 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package block 6 7 import ( 8 "fmt" 9 "path/filepath" 10 "reflect" 11 "strings" 12 "testing" 13 14 "github.com/mvdan/u-root-coreutils/pkg/pci" 15 "github.com/mvdan/u-root-coreutils/pkg/testutil" 16 ) 17 18 func TestDebug(t *testing.T) { 19 Debug("foo") 20 } 21 22 func TestDeviceError(t *testing.T) { 23 // Success paths are covered in vm_test.go 24 _, err := Device("noexist") 25 if err == nil { 26 t.Errorf(`Device("noexist") = _,%v, expect an error`, err) 27 } 28 } 29 30 func TestBlockDevString(t *testing.T) { 31 for _, tt := range []struct { 32 name string 33 blockdev *BlockDev 34 want []string 35 }{ 36 { 37 name: "complete", 38 blockdev: &BlockDev{ 39 Name: "devname", 40 FSType: "sometype", 41 FsUUID: "xxxx", 42 }, 43 want: []string{"devname", "sometype", "xxxx"}, 44 }, 45 { 46 name: "without FSType", 47 blockdev: &BlockDev{ 48 Name: "devname", 49 FsUUID: "xxxx", 50 }, 51 want: []string{"devname", "xxxx"}, 52 }, 53 { 54 name: "without FSType and FsUUID", 55 blockdev: &BlockDev{ 56 Name: "devname", 57 }, 58 want: []string{"devname"}, 59 }, 60 } { 61 t.Run(tt.name, func(t *testing.T) { 62 got := tt.blockdev.String() 63 for _, w := range tt.want { 64 if !strings.Contains(got, w) { 65 t.Errorf("String() = %s, does not contain %s", got, w) 66 } 67 } 68 69 }) 70 } 71 } 72 73 func TestBlockDevDevicePath(t *testing.T) { 74 name := "devname" 75 b := &BlockDev{Name: name} 76 want := filepath.Join("/dev", name) 77 got := b.DevicePath() 78 if got != want { 79 t.Errorf("DevicePath() = %s, want %s", got, want) 80 } 81 } 82 83 func TestBlockDevDeviceName(t *testing.T) { 84 want := "devname" 85 b := &BlockDev{Name: want} 86 got := b.DevName() 87 if got != want { 88 t.Errorf("DevName() = %s, want %s", got, want) 89 } 90 } 91 92 func TestBlockDevGPTTableError(t *testing.T) { 93 // Success paths are covered in vm_test.go 94 tests := []struct { 95 name string 96 dev *BlockDev 97 }{ 98 { 99 name: "Empty BlockDev", 100 dev: &BlockDev{}, 101 }, 102 { 103 name: "Not exist", 104 dev: &BlockDev{Name: "noexist"}, 105 }, 106 } 107 108 for _, tt := range tests { 109 t.Run(tt.name, func(t *testing.T) { 110 _, err := tt.dev.GPTTable() 111 if err == nil { 112 t.Error("Expect an error") 113 } 114 }) 115 } 116 } 117 118 func TestBlockDevPhysicalBlockSizeError(t *testing.T) { 119 // Success paths are covered in vm_test.go 120 dev := &BlockDev{Name: "noexist"} 121 _, err := dev.PhysicalBlockSize() 122 if err == nil { 123 t.Error("Expect an error") 124 } 125 } 126 127 func TestBlockDevBlockSizeError(t *testing.T) { 128 // Success paths are covered in vm_test.go 129 dev := &BlockDev{Name: "noexist"} 130 _, err := dev.BlockSize() 131 if err == nil { 132 t.Error("Expect an error") 133 } 134 } 135 136 func TestBlockDevKernelBlockSizeError(t *testing.T) { 137 // Success paths are covered in vm_test.go 138 dev := &BlockDev{Name: "noexist"} 139 _, err := dev.KernelBlockSize() 140 if err == nil { 141 t.Error("Expect an error") 142 } 143 } 144 145 func TestBlockDevSizeError(t *testing.T) { 146 // Success paths are covered in vm_test.go 147 tests := []struct { 148 name string 149 dev *BlockDev 150 }{ 151 { 152 name: "Empty BlockDev", 153 dev: &BlockDev{}, 154 }, 155 { 156 name: "Not exist", 157 dev: &BlockDev{Name: "noexist"}, 158 }, 159 } 160 161 for _, tt := range tests { 162 t.Run(tt.name, func(t *testing.T) { 163 _, err := tt.dev.Size() 164 if err == nil { 165 t.Error("Expect an error") 166 } 167 }) 168 } 169 } 170 171 func TestBlockDevReadPartitionTableError(t *testing.T) { 172 // Success paths are covered in vm_test.go 173 dev := &BlockDev{Name: "noexist"} 174 err := dev.ReadPartitionTable() 175 if err == nil { 176 t.Error("Expect an error") 177 } 178 } 179 180 func TestBlockDevPCIInfoError(t *testing.T) { 181 // Success paths are covered in vm_test.go 182 dev := &BlockDev{Name: "noexist"} 183 _, err := dev.PCIInfo() 184 if err == nil { 185 t.Error("Expect an error") 186 } 187 } 188 189 func TestBlockDevicesFilterName(t *testing.T) { 190 191 devs := BlockDevices{ 192 &BlockDev{Name: "devA", FsUUID: "1234-abcd"}, 193 &BlockDev{Name: "devB", FsUUID: "abcd-1234"}, 194 &BlockDev{Name: "devC", FsUUID: "1a2b-3c4d"}, 195 } 196 197 devs = devs.FilterName("devB") 198 199 want := BlockDevices{ 200 &BlockDev{Name: "devB", FsUUID: "abcd-1234"}, 201 } 202 if !reflect.DeepEqual(devs, want) { 203 t.Fatalf("Filtered block devices: \n\t%v \nwant: \n\t%v", devs, want) 204 } 205 } 206 207 func TestBlockDevicesFilterNames(t *testing.T) { 208 209 devs := BlockDevices{ 210 &BlockDev{Name: "devA", FsUUID: "1234-abcd"}, 211 &BlockDev{Name: "devB", FsUUID: "abcd-1234"}, 212 &BlockDev{Name: "devC", FsUUID: "1a2b-3c4d"}, 213 } 214 215 devs = devs.FilterNames("devA", "devB") 216 217 want := BlockDevices{ 218 &BlockDev{Name: "devA", FsUUID: "1234-abcd"}, 219 &BlockDev{Name: "devB", FsUUID: "abcd-1234"}, 220 } 221 if !reflect.DeepEqual(devs, want) { 222 t.Fatalf("Filtered block devices: \n\t%v \nwant: \n\t%v", devs, want) 223 } 224 } 225 226 func TestBlockDevicesFilterFSUUID(t *testing.T) { 227 228 devs := BlockDevices{ 229 &BlockDev{Name: "devA", FsUUID: "1234-abcd"}, 230 &BlockDev{Name: "devB", FsUUID: "abcd-1234"}, 231 &BlockDev{Name: "devC", FsUUID: "1a2b-3c4d"}, 232 } 233 234 devs = devs.FilterFSUUID("abcd-1234") 235 236 want := BlockDevices{ 237 &BlockDev{Name: "devB", FsUUID: "abcd-1234"}, 238 } 239 if !reflect.DeepEqual(devs, want) { 240 t.Fatalf("Filtered block devices: \n\t%v \nwant: \n\t%v", devs, want) 241 } 242 } 243 244 func TestGetMountpointByDevice(t *testing.T) { 245 LinuxMountsPath = "testdata/mounts" 246 247 t.Run("Not exist", func(t *testing.T) { 248 if _, err := GetMountpointByDevice("/dev/mapper/sys-oldxxxxxx"); err == nil { 249 t.Errorf(`GetMountpointByDevice("/dev/mapper/sys-oldxxxxxx") = _, %v, expect an error`, err) 250 } 251 }) 252 253 t.Run("Valid", func(t *testing.T) { 254 mountpoint, err := GetMountpointByDevice("/dev/mapper/sys-old") 255 if err != nil { 256 t.Errorf(`GetMountpointByDevice("/dev/mapper/sys-old") = _, %v, unexpected error`, err) 257 } 258 if *mountpoint != "/media/usb" { 259 t.Errorf(`*mountpoint = %q, want "/media/usb"`, *mountpoint) 260 } 261 }) 262 } 263 264 func TestParsePCIBlockList(t *testing.T) { 265 for _, tt := range []struct { 266 name string 267 blockString string 268 want pci.Devices 269 errStr string 270 }{ 271 { 272 name: "one device", 273 blockString: "0x8086:0x1234", 274 want: pci.Devices{&pci.PCI{Vendor: 0x8086, Device: 0x1234}}, 275 errStr: "", 276 }, 277 { 278 name: "two devices", 279 blockString: "0x8086:0x1234,0x1234:0xabcd", 280 want: pci.Devices{ 281 &pci.PCI{Vendor: 0x8086, Device: 0x1234}, 282 &pci.PCI{Vendor: 0x1234, Device: 0xabcd}, 283 }, 284 errStr: "", 285 }, 286 { 287 name: "no 0x", 288 blockString: "8086:1234,1234:abcd", 289 want: pci.Devices{ 290 &pci.PCI{Vendor: 0x8086, Device: 0x1234}, 291 &pci.PCI{Vendor: 0x1234, Device: 0xabcd}, 292 }, 293 errStr: "", 294 }, 295 { 296 name: "capitals", 297 blockString: "0x8086:0x1234,0x1234:0xABCD", 298 want: pci.Devices{ 299 &pci.PCI{Vendor: 0x8086, Device: 0x1234}, 300 &pci.PCI{Vendor: 0x1234, Device: 0xabcd}, 301 }, 302 errStr: "", 303 }, 304 { 305 name: "not hex vendor", 306 blockString: "0xghij:0x1234", 307 want: nil, 308 errStr: "BlockList needs to contain a hex vendor ID, got 0xghij, err strconv.ParseUint: parsing \"ghij\": invalid syntax", 309 }, 310 { 311 name: "not hex vendor", 312 blockString: "0x1234:0xghij", 313 want: nil, 314 errStr: "BlockList needs to contain a hex device ID, got 0xghij, err strconv.ParseUint: parsing \"ghij\": invalid syntax", 315 }, 316 { 317 name: "bad format", 318 blockString: "0xghij,0x1234", 319 want: nil, 320 errStr: "BlockList needs to be of format vendor1:device1,vendor2:device2...! got 0xghij,0x1234", 321 }, 322 } { 323 t.Run(tt.name, func(t *testing.T) { 324 devices, err := parsePCIBlockList(tt.blockString) 325 if e := testutil.CheckError(err, tt.errStr); e != nil { 326 t.Errorf(`testutil.CheckError(%v, %q) = %v, want nil`, err, tt.errStr, e) 327 } 328 if !reflect.DeepEqual(devices, tt.want) { 329 // Need to do this because stringer does not print device and vendor 330 s := "got:\n" 331 for _, d := range devices { 332 s = fmt.Sprintf("%s{Vendor: %v, Device %v}\n", s, d.Vendor, d.Device) 333 } 334 s = fmt.Sprintf("%swant:\n", s) 335 for _, d := range tt.want { 336 s = fmt.Sprintf("%s{Vendor: %v, Device %v}\n", s, d.Vendor, d.Device) 337 } 338 t.Errorf("reflect.DeepEqual(%v, %v) = false, want true", devices, tt.want) 339 } 340 }) 341 } 342 } 343 344 func TestComposePartName(t *testing.T) { 345 for _, tt := range []struct { 346 name string 347 devName string 348 partNo int 349 want string 350 }{ 351 { 352 name: "parent device name ends with a letter #1", 353 devName: "sda", 354 partNo: 1, 355 want: "sda1", 356 }, 357 { 358 name: "parent device name ends with a letter #2", 359 devName: "sdb", 360 partNo: 1, 361 want: "sdb1", 362 }, 363 { 364 name: "parent device name ends with a letter #3", 365 devName: "sda", 366 partNo: 2, 367 want: "sda2", 368 }, 369 { 370 name: "parent device name ends with a letter #4", 371 devName: "sdb", 372 partNo: 2, 373 want: "sdb2", 374 }, 375 { 376 name: "parent device name ends with a letter, more than 9 partitions", 377 devName: "sda", 378 partNo: 11, 379 want: "sda11", 380 }, 381 { 382 name: "parent device name ends with a number #1", 383 devName: "nvme0n1", 384 partNo: 1, 385 want: "nvme0n1p1", 386 }, 387 { 388 name: "parent device name ends with a number #2", 389 devName: "nvme0n1", 390 partNo: 2, 391 want: "nvme0n1p2", 392 }, 393 { 394 name: "parent device name ends with a number, more than 9 devices", 395 devName: "nvme0n10", 396 partNo: 1, 397 want: "nvme0n10p1", 398 }, 399 { 400 name: "parent device name ends with a number, more than 9 partitions", 401 devName: "nvme0n1", 402 partNo: 10, 403 want: "nvme0n1p10", 404 }, 405 { 406 name: "parent device name ends with a number, more than 9 devices ans partitions", 407 devName: "nvme0n10", 408 partNo: 10, 409 want: "nvme0n10p10", 410 }, 411 } { 412 t.Run(tt.name, func(t *testing.T) { 413 got := ComposePartName(tt.devName, tt.partNo) 414 if got != tt.want { 415 t.Errorf("ComposePartName(%q, %d) = %q, want %q", tt.devName, tt.partNo, got, tt.want) 416 } 417 }) 418 } 419 }