github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/boot/esxi/esxi_test.go (about)

     1  // Copyright 2019 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 esxi
     6  
     7  import (
     8  	"encoding/hex"
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"reflect"
    13  	"testing"
    14  
    15  	"github.com/mvdan/u-root-coreutils/pkg/boot"
    16  	"github.com/mvdan/u-root-coreutils/pkg/boot/multiboot"
    17  	"github.com/mvdan/u-root-coreutils/pkg/uio"
    18  )
    19  
    20  func TestParse(t *testing.T) {
    21  	for _, tt := range []struct {
    22  		file string
    23  		want options
    24  	}{
    25  		{
    26  			file: "testdata/kernel_cmdline_mods.cfg",
    27  			want: options{
    28  				title:  "VMware ESXi",
    29  				kernel: "testdata/b.b00",
    30  				args:   "b.b00 zee",
    31  				modules: []module{
    32  					{
    33  						path:    "testdata/b.b00",
    34  						cmdline: "b.b00 blabla",
    35  					},
    36  					{
    37  						path:    "testdata/k.b00",
    38  						cmdline: "k.b00",
    39  					},
    40  					{
    41  						path:    "testdata/m.m00",
    42  						cmdline: "m.m00 marg marg2",
    43  					},
    44  				},
    45  			},
    46  		},
    47  		{
    48  			file: "testdata/kernelopt_first.cfg",
    49  			want: options{
    50  				title:  "VMware ESXi",
    51  				kernel: "testdata/b.b00",
    52  				args:   "b.b00 zee",
    53  			},
    54  		},
    55  		{
    56  			file: "testdata/empty_mods.cfg",
    57  			want: options{
    58  				title:  "VMware ESXi",
    59  				kernel: "testdata/b.b00",
    60  				args:   "b.b00 zee",
    61  			},
    62  		},
    63  		{
    64  			file: "testdata/no_mods.cfg",
    65  			want: options{
    66  				title:  "VMware ESXi",
    67  				kernel: "testdata/b.b00",
    68  				args:   "b.b00 zee",
    69  			},
    70  		},
    71  		{
    72  			file: "testdata/no_cmdline.cfg",
    73  			want: options{
    74  				title:  "VMware ESXi",
    75  				kernel: "testdata/b.b00",
    76  				args:   "b.b00 ",
    77  			},
    78  		},
    79  		{
    80  			file: "testdata/empty_cmdline.cfg",
    81  			want: options{
    82  				title:  "VMware ESXi",
    83  				kernel: "testdata/b.b00",
    84  				args:   "b.b00 ",
    85  			},
    86  		},
    87  		{
    88  			file: "testdata/empty_updated.cfg",
    89  			want: options{
    90  				title:  "VMware ESXi",
    91  				kernel: "testdata/b.b00",
    92  				args:   "b.b00 zee",
    93  				// Explicitly stating this as the wanted value.
    94  				updated: 0,
    95  			},
    96  		},
    97  		{
    98  			file: "testdata/updated_twice.cfg",
    99  			want: options{
   100  				title:  "VMware ESXi",
   101  				kernel: "testdata/b.b00",
   102  				args:   "b.b00 zee",
   103  				// Explicitly stating this as the wanted value.
   104  				updated: 0,
   105  			},
   106  		},
   107  		{
   108  			file: "testdata/updated.cfg",
   109  			want: options{
   110  				title:   "VMware ESXi",
   111  				kernel:  "testdata/b.b00",
   112  				args:    "b.b00 zee",
   113  				updated: 4,
   114  			},
   115  		},
   116  		{
   117  			file: "testdata/empty_bootstate.cfg",
   118  			want: options{
   119  				title:  "VMware ESXi",
   120  				kernel: "testdata/b.b00",
   121  				args:   "b.b00 zee",
   122  				// Explicitly stating this as the wanted value.
   123  				bootstate: bootValid,
   124  			},
   125  		},
   126  		{
   127  			file: "testdata/bootstate_twice.cfg",
   128  			want: options{
   129  				title:  "VMware ESXi",
   130  				kernel: "testdata/b.b00",
   131  				args:   "b.b00 zee",
   132  				// Explicitly stating this as the wanted value.
   133  				bootstate: bootValid,
   134  			},
   135  		},
   136  		{
   137  			file: "testdata/bootstate.cfg",
   138  			want: options{
   139  				title:     "VMware ESXi",
   140  				kernel:    "testdata/b.b00",
   141  				args:      "b.b00 zee",
   142  				bootstate: bootDirty,
   143  			},
   144  		},
   145  		{
   146  			file: "testdata/bootstate_invalid.cfg",
   147  			want: options{
   148  				title:     "VMware ESXi",
   149  				kernel:    "testdata/b.b00",
   150  				args:      "b.b00 zee",
   151  				bootstate: bootInvalid,
   152  			},
   153  		},
   154  		{
   155  			file: "testdata/no_bootstate.cfg",
   156  			want: options{
   157  				title:     "VMware ESXi",
   158  				kernel:    "testdata/b.b00",
   159  				args:      "b.b00 zee",
   160  				bootstate: bootInvalid,
   161  			},
   162  		},
   163  	} {
   164  		got, err := parse(tt.file)
   165  		if err != nil {
   166  			t.Fatalf("cannot parse config at %s: %v", tt.file, err)
   167  		}
   168  
   169  		if !reflect.DeepEqual(got, tt.want) {
   170  			t.Errorf("LoadConfig(%s) = %#v want %#v", tt.file, got, tt.want)
   171  		}
   172  	}
   173  }
   174  
   175  // This is in the second block of testdata/dev5 and testdata/dev6.
   176  var (
   177  	dev5GUID = "aabbccddeeff0011"
   178  	dev6GUID = "00112233445566aa"
   179  	uuid5    = hex.EncodeToString([]byte(dev5GUID))
   180  	uuid6    = hex.EncodeToString([]byte(dev6GUID))
   181  	device   = "testdata/dev"
   182  )
   183  
   184  // Poor man's equal.
   185  //
   186  // the Kernel and Modules fields will be full of uio.NewLazyFiles. We just want
   187  // them to be pointing to the same file name; we can't compare the function
   188  // pointers obviously. Lazy files will always print their name.
   189  func multibootEqual(a, b []*boot.MultibootImage) bool {
   190  	return fmt.Sprintf("%v", a) == fmt.Sprintf("%v", b)
   191  }
   192  
   193  func TestDev5Valid(t *testing.T) {
   194  	want := []*boot.MultibootImage{
   195  		{
   196  			Name:    "VMware ESXi from testdata/dev5",
   197  			Kernel:  uio.NewLazyFile("testdata/k"),
   198  			Cmdline: fmt.Sprintf(" bootUUID=%s", uuid5),
   199  			Modules: []multiboot.Module{},
   200  		},
   201  	}
   202  
   203  	opts5 := &options{
   204  		title:     "VMware ESXi",
   205  		kernel:    "testdata/k",
   206  		updated:   1,
   207  		bootstate: bootValid,
   208  	}
   209  
   210  	// No opts6 at all.
   211  	imgs, _ := getImages(device, opts5, nil)
   212  	if !multibootEqual(imgs, want) {
   213  		t.Fatalf("getImages(%s, %v, %v) = %v, want %v", device, opts5, nil, imgs, want)
   214  	}
   215  
   216  	// Invalid opts6. Higher updated, but invalid state.
   217  	invalidOpts6 := &options{
   218  		title:     "VMware ESXi",
   219  		kernel:    "foobar",
   220  		updated:   2,
   221  		bootstate: bootInvalid,
   222  	}
   223  	imgs, _ = getImages(device, opts5, invalidOpts6)
   224  	if !multibootEqual(imgs, want) {
   225  		t.Fatalf("getImages(%s, %v, %v) = %v, want %v", device, opts5, invalidOpts6, imgs, want)
   226  	}
   227  }
   228  
   229  func TestDev6Valid(t *testing.T) {
   230  	want := []*boot.MultibootImage{
   231  		{
   232  			Name:    "VMware ESXi from testdata/dev6",
   233  			Kernel:  uio.NewLazyFile("testdata/k"),
   234  			Cmdline: fmt.Sprintf(" bootUUID=%s", uuid6),
   235  			Modules: []multiboot.Module{},
   236  		},
   237  	}
   238  
   239  	opts6 := &options{
   240  		title:     "VMware ESXi",
   241  		kernel:    "testdata/k",
   242  		updated:   1,
   243  		bootstate: bootValid,
   244  	}
   245  
   246  	// No opts5 at all.
   247  	imgs, err := getImages(device, nil, opts6)
   248  	if !multibootEqual(imgs, want) {
   249  		t.Fatalf("getImages(%s, %v, %v) = %v, want %v (err %v)", device, nil, opts6, imgs, want, err)
   250  	}
   251  
   252  	// Invalid opts5. Higher updated, but invalid state.
   253  	invalidOpts5 := &options{
   254  		title:     "VMware ESXi",
   255  		kernel:    "foobar",
   256  		updated:   2,
   257  		bootstate: bootInvalid,
   258  	}
   259  	imgs, _ = getImages(device, invalidOpts5, opts6)
   260  	if !multibootEqual(imgs, want) {
   261  		t.Fatalf("getImages(%s, %v, %v) = %v, want %v", device, invalidOpts5, opts6, imgs, want)
   262  	}
   263  }
   264  
   265  func TestImageOrder(t *testing.T) {
   266  	prevGetBlockSize := getBlockSize
   267  	defer func() {
   268  		getBlockSize = prevGetBlockSize
   269  	}()
   270  	getBlockSize = func(dev string) (int, error) {
   271  		return 512, nil
   272  	}
   273  
   274  	opt5 := &options{
   275  		title:     "VMware ESXi",
   276  		kernel:    "foobar",
   277  		updated:   2,
   278  		bootstate: bootValid,
   279  	}
   280  	want5 := &boot.MultibootImage{
   281  		Name:    "VMware ESXi from testdata/dev5",
   282  		Kernel:  uio.NewLazyFile("foobar"),
   283  		Cmdline: fmt.Sprintf(" bootUUID=%s", uuid5),
   284  		Modules: []multiboot.Module{},
   285  	}
   286  
   287  	opt6 := &options{
   288  		title:     "VMware ESXi",
   289  		kernel:    "testdata/k",
   290  		updated:   1,
   291  		bootstate: bootValid,
   292  	}
   293  	want6 := &boot.MultibootImage{
   294  		Name:    "VMware ESXi from testdata/dev6",
   295  		Kernel:  uio.NewLazyFile("testdata/k"),
   296  		Cmdline: fmt.Sprintf(" bootUUID=%s", uuid6),
   297  		Modules: []multiboot.Module{},
   298  	}
   299  
   300  	// Way 1.
   301  	want := []*boot.MultibootImage{want5, want6}
   302  	imgs, _ := getImages(device, opt5, opt6)
   303  	if !multibootEqual(imgs, want) {
   304  		t.Fatalf("getImages(%s, %v, %v) = %v, want %v", device, opt5, opt6, imgs, want)
   305  	}
   306  
   307  	opt5.updated = 1
   308  	opt6.updated = 2
   309  	// Vice versa priority.
   310  	want = []*boot.MultibootImage{want6, want5}
   311  	imgs, _ = getImages(device, opt5, opt6)
   312  	if !multibootEqual(imgs, want) {
   313  		t.Fatalf("getImages(%s, %v, %v) = %v, want %v", device, opt5, opt6, imgs, want)
   314  	}
   315  }
   316  
   317  func FuzzParse(f *testing.F) {
   318  	seeds, err := filepath.Glob("testdata/*.cfg")
   319  	if err != nil {
   320  		f.Fatalf("failed to find seed corpora files: %v", err)
   321  	}
   322  	for _, seed := range seeds {
   323  		seedBytes, err := os.ReadFile(seed)
   324  		if err != nil {
   325  			f.Fatalf("failed read seed corpora from files %v: %v", seed, err)
   326  		}
   327  
   328  		f.Add(seedBytes)
   329  	}
   330  	f.Fuzz(func(t *testing.T, data []byte) {
   331  		if len(data) > 4096 {
   332  			return
   333  		}
   334  
   335  		parse(string(data))
   336  	})
   337  }