github.com/andrewsun2898/u-root@v6.0.1-0.20200616011413-4b2895c1b815+incompatible/pkg/uroot/uroot_test.go (about)

     1  // Copyright 2018 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 uroot
     6  
     7  import (
     8  	"fmt"
     9  	"io/ioutil"
    10  	"log"
    11  	"os"
    12  	"path/filepath"
    13  	"reflect"
    14  	"syscall"
    15  	"testing"
    16  
    17  	"github.com/u-root/u-root/pkg/cpio"
    18  	"github.com/u-root/u-root/pkg/golang"
    19  	"github.com/u-root/u-root/pkg/uroot/builder"
    20  	itest "github.com/u-root/u-root/pkg/uroot/initramfs/test"
    21  )
    22  
    23  type inMemArchive struct {
    24  	*cpio.Archive
    25  }
    26  
    27  // Finish implements initramfs.Writer.Finish.
    28  func (inMemArchive) Finish() error { return nil }
    29  
    30  func TestResolvePackagePaths(t *testing.T) {
    31  	defaultEnv := golang.Default()
    32  	gopath1, err := filepath.Abs("test/gopath1")
    33  	if err != nil {
    34  		t.Fatalf("failure to set up test: %v", err)
    35  	}
    36  	gopath2, err := filepath.Abs("test/gopath2")
    37  	if err != nil {
    38  		t.Fatalf("failure to set up test: %v", err)
    39  	}
    40  	gopath1Env := defaultEnv
    41  	gopath1Env.GOPATH = gopath1
    42  	gopath2Env := defaultEnv
    43  	gopath2Env.GOPATH = gopath2
    44  	everythingEnv := defaultEnv
    45  	everythingEnv.GOPATH = gopath1 + ":" + gopath2
    46  	foopath, err := filepath.Abs("test/gopath1/src/foo")
    47  	if err != nil {
    48  		t.Fatalf("failure to set up test: %v", err)
    49  	}
    50  
    51  	// Why doesn't the log package export this as a default?
    52  	l := log.New(os.Stdout, "", log.LstdFlags)
    53  
    54  	for _, tc := range []struct {
    55  		env      golang.Environ
    56  		in       []string
    57  		expected []string
    58  		wantErr  bool
    59  	}{
    60  		// Nonexistent Package
    61  		{
    62  			env:      defaultEnv,
    63  			in:       []string{"fakepackagename"},
    64  			expected: nil,
    65  			wantErr:  true,
    66  		},
    67  		// Single go package import
    68  		{
    69  			env: defaultEnv,
    70  			in:  []string{"github.com/u-root/u-root/cmds/core/ls"},
    71  			// We expect the full URL format because that's the path in our default GOPATH
    72  			expected: []string{"github.com/u-root/u-root/cmds/core/ls"},
    73  			wantErr:  false,
    74  		},
    75  		// Single package directory relative to working dir
    76  		{
    77  			env:      defaultEnv,
    78  			in:       []string{"test/gopath1/src/foo"},
    79  			expected: []string{"github.com/u-root/u-root/pkg/uroot/test/gopath1/src/foo"},
    80  			wantErr:  false,
    81  		},
    82  		// Single package directory with absolute path
    83  		{
    84  			env:      defaultEnv,
    85  			in:       []string{foopath},
    86  			expected: []string{"github.com/u-root/u-root/pkg/uroot/test/gopath1/src/foo"},
    87  			wantErr:  false,
    88  		},
    89  		// Single package directory relative to GOPATH
    90  		{
    91  			env: gopath1Env,
    92  			in:  []string{"foo"},
    93  			expected: []string{
    94  				"foo",
    95  			},
    96  			wantErr: false,
    97  		},
    98  		// Package directory glob
    99  		{
   100  			env: defaultEnv,
   101  			in:  []string{"test/gopath2/src/mypkg*"},
   102  			expected: []string{
   103  				"github.com/u-root/u-root/pkg/uroot/test/gopath2/src/mypkga",
   104  				"github.com/u-root/u-root/pkg/uroot/test/gopath2/src/mypkgb",
   105  			},
   106  			wantErr: false,
   107  		},
   108  		// GOPATH glob
   109  		{
   110  			env: gopath2Env,
   111  			in:  []string{"mypkg*"},
   112  			expected: []string{
   113  				"mypkga",
   114  				"mypkgb",
   115  			},
   116  			wantErr: false,
   117  		},
   118  		// Single ambiguous package - exists in both GOROOT and GOPATH
   119  		{
   120  			env: gopath1Env,
   121  			in:  []string{"os"},
   122  			expected: []string{
   123  				"os",
   124  			},
   125  			wantErr: false,
   126  		},
   127  		// Packages from different gopaths
   128  		{
   129  			env: everythingEnv,
   130  			in:  []string{"foo", "mypkga"},
   131  			expected: []string{
   132  				"foo",
   133  				"mypkga",
   134  			},
   135  			wantErr: false,
   136  		},
   137  		// Same package specified twice
   138  		{
   139  			env: defaultEnv,
   140  			in:  []string{"test/gopath2/src/mypkga", "test/gopath2/src/mypkga"},
   141  			// TODO: This returns the package twice. Is this preferred?
   142  			expected: []string{
   143  				"github.com/u-root/u-root/pkg/uroot/test/gopath2/src/mypkga",
   144  				"github.com/u-root/u-root/pkg/uroot/test/gopath2/src/mypkga",
   145  			},
   146  			wantErr: false,
   147  		},
   148  	} {
   149  		t.Run(fmt.Sprintf("%q", tc.in), func(t *testing.T) {
   150  			out, err := ResolvePackagePaths(l, tc.env, tc.in)
   151  			if (err != nil) != tc.wantErr {
   152  				t.Fatalf("ResolvePackagePaths(%#v, %v) err != nil is %v, want %v\nerr is %v",
   153  					tc.env, tc.in, err != nil, tc.wantErr, err)
   154  			}
   155  			if !reflect.DeepEqual(out, tc.expected) {
   156  				t.Errorf("ResolvePackagePaths(%#v, %v) = %v; want %v",
   157  					tc.env, tc.in, out, tc.expected)
   158  			}
   159  		})
   160  	}
   161  }
   162  
   163  func TestCreateInitramfs(t *testing.T) {
   164  	dir, err := ioutil.TempDir("", "foo")
   165  	if err != nil {
   166  		t.Error(err)
   167  	}
   168  	defer os.RemoveAll(dir)
   169  	syscall.Umask(0)
   170  
   171  	tmp777 := filepath.Join(dir, "tmp777")
   172  	if err := os.MkdirAll(tmp777, 0777); err != nil {
   173  		t.Error(err)
   174  	}
   175  
   176  	// Why doesn't the log package export this as a default?
   177  	l := log.New(os.Stdout, "", log.LstdFlags)
   178  
   179  	for i, tt := range []struct {
   180  		name       string
   181  		opts       Opts
   182  		want       string
   183  		validators []itest.ArchiveValidator
   184  	}{
   185  		{
   186  			name: "BB archive with ls and init",
   187  			opts: Opts{
   188  				Env:             golang.Default(),
   189  				TempDir:         dir,
   190  				ExtraFiles:      nil,
   191  				UseExistingInit: false,
   192  				InitCmd:         "init",
   193  				DefaultShell:    "ls",
   194  				Commands: []Commands{
   195  					{
   196  						Builder: builder.BusyBox,
   197  						Packages: []string{
   198  							"github.com/u-root/u-root/cmds/core/init",
   199  							"github.com/u-root/u-root/cmds/core/ls",
   200  						},
   201  					},
   202  				},
   203  			},
   204  			want: "",
   205  			validators: []itest.ArchiveValidator{
   206  				itest.HasFile{"bbin/bb"},
   207  				itest.HasRecord{cpio.Symlink("bbin/init", "bb")},
   208  				itest.HasRecord{cpio.Symlink("bbin/ls", "bb")},
   209  				itest.HasRecord{cpio.Symlink("bin/defaultsh", "../bbin/ls")},
   210  				itest.HasRecord{cpio.Symlink("bin/sh", "../bbin/ls")},
   211  			},
   212  		},
   213  		{
   214  			name: "no temp dir",
   215  			opts: Opts{
   216  				Env:          golang.Default(),
   217  				InitCmd:      "init",
   218  				DefaultShell: "",
   219  			},
   220  			want: "temp dir \"\" must exist: stat : no such file or directory",
   221  			validators: []itest.ArchiveValidator{
   222  				itest.IsEmpty{},
   223  			},
   224  		},
   225  		{
   226  			name: "no commands",
   227  			opts: Opts{
   228  				Env:     golang.Default(),
   229  				TempDir: dir,
   230  			},
   231  			want: "",
   232  			validators: []itest.ArchiveValidator{
   233  				itest.MissingFile{"bbin/bb"},
   234  			},
   235  		},
   236  		{
   237  			name: "init specified, but not in commands",
   238  			opts: Opts{
   239  				Commands: []Commands{
   240  					{
   241  						Builder: builder.Binary,
   242  						Packages: []string{
   243  							"github.com/u-root/u-root/cmds/core/ls",
   244  						},
   245  					},
   246  				},
   247  				Env:          golang.Default(),
   248  				TempDir:      dir,
   249  				DefaultShell: "zoocar",
   250  				InitCmd:      "foobar",
   251  			},
   252  			want: "could not create symlink from \"init\" to \"foobar\": command or path \"foobar\" not included in u-root build: specify -initcmd=\"\" to ignore this error and build without an init",
   253  			validators: []itest.ArchiveValidator{
   254  				itest.IsEmpty{},
   255  			},
   256  		},
   257  		{
   258  			name: "init symlinked to absolute path",
   259  			opts: Opts{
   260  				Env:     golang.Default(),
   261  				TempDir: dir,
   262  				InitCmd: "/bin/systemd",
   263  			},
   264  			want: "",
   265  			validators: []itest.ArchiveValidator{
   266  				itest.HasRecord{cpio.Symlink("init", "bin/systemd")},
   267  			},
   268  		},
   269  		{
   270  			name: "multi-mode archive",
   271  			opts: Opts{
   272  				Env:             golang.Default(),
   273  				TempDir:         dir,
   274  				ExtraFiles:      nil,
   275  				UseExistingInit: false,
   276  				InitCmd:         "init",
   277  				DefaultShell:    "ls",
   278  				Commands: []Commands{
   279  					{
   280  						Builder: builder.BusyBox,
   281  						Packages: []string{
   282  							"github.com/u-root/u-root/cmds/core/init",
   283  							"github.com/u-root/u-root/cmds/core/ls",
   284  						},
   285  					},
   286  					{
   287  						Builder: builder.Binary,
   288  						Packages: []string{
   289  							"github.com/u-root/u-root/cmds/core/cp",
   290  							"github.com/u-root/u-root/cmds/core/dd",
   291  						},
   292  					},
   293  					{
   294  						Builder: builder.Source,
   295  						Packages: []string{
   296  							"github.com/u-root/u-root/cmds/core/cat",
   297  							"github.com/u-root/u-root/cmds/core/chroot",
   298  							"github.com/u-root/u-root/cmds/core/installcommand",
   299  						},
   300  					},
   301  				},
   302  			},
   303  			want: "",
   304  			validators: []itest.ArchiveValidator{
   305  				itest.HasRecord{cpio.Symlink("init", "bbin/init")},
   306  
   307  				// bb mode.
   308  				itest.HasFile{"bbin/bb"},
   309  				itest.HasRecord{cpio.Symlink("bbin/init", "bb")},
   310  				itest.HasRecord{cpio.Symlink("bbin/ls", "bb")},
   311  				itest.HasRecord{cpio.Symlink("bin/defaultsh", "../bbin/ls")},
   312  				itest.HasRecord{cpio.Symlink("bin/sh", "../bbin/ls")},
   313  
   314  				// binary mode.
   315  				itest.HasFile{"bin/cp"},
   316  				itest.HasFile{"bin/dd"},
   317  
   318  				// source mode.
   319  				itest.HasRecord{cpio.Symlink("buildbin/cat", "installcommand")},
   320  				itest.HasRecord{cpio.Symlink("buildbin/chroot", "installcommand")},
   321  				itest.HasFile{"buildbin/installcommand"},
   322  				itest.HasFile{"src/github.com/u-root/u-root/cmds/core/cat/cat.go"},
   323  				itest.HasFile{"src/github.com/u-root/u-root/cmds/core/chroot/chroot.go"},
   324  				itest.HasFile{"src/github.com/u-root/u-root/cmds/core/installcommand/installcommand.go"},
   325  			},
   326  		},
   327  	} {
   328  		t.Run(fmt.Sprintf("Test %d [%s]", i, tt.name), func(t *testing.T) {
   329  			archive := inMemArchive{cpio.InMemArchive()}
   330  			tt.opts.OutputFile = archive
   331  			// Compare error type or error string.
   332  			if err := CreateInitramfs(l, tt.opts); (err != nil && err.Error() != tt.want) || (len(tt.want) > 0 && err == nil) {
   333  				t.Errorf("CreateInitramfs(%v) = %v, want %v", tt.opts, err, tt.want)
   334  			}
   335  
   336  			for _, v := range tt.validators {
   337  				if err := v.Validate(archive.Archive); err != nil {
   338  					t.Errorf("validator failed: %v / archive:\n%s", err, archive)
   339  				}
   340  			}
   341  		})
   342  	}
   343  }