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  }