github.com/shaardie/u-root@v4.0.1-0.20190127173353-f24a1c26aa2e+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/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/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       error
   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/init",
   199  							"github.com/u-root/u-root/cmds/ls",
   200  						},
   201  					},
   202  				},
   203  			},
   204  			want: nil,
   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  			// TODO: Ew. Our error types suck.
   221  			want: fmt.Errorf("temp dir \"\" must exist: stat : no such file or directory"),
   222  			validators: []itest.ArchiveValidator{
   223  				itest.IsEmpty{},
   224  			},
   225  		},
   226  		{
   227  			name: "no commands",
   228  			opts: Opts{
   229  				Env:     golang.Default(),
   230  				TempDir: dir,
   231  			},
   232  			want: nil,
   233  			validators: []itest.ArchiveValidator{
   234  				itest.MissingFile{"bbin/bb"},
   235  			},
   236  		},
   237  		{
   238  			name: "init specified, but not in commands",
   239  			opts: Opts{
   240  				Commands: []Commands{
   241  					{
   242  						Builder: builder.Binary,
   243  						Packages: []string{
   244  							"github.com/u-root/u-root/cmds/ls",
   245  						},
   246  					},
   247  				},
   248  				Env:          golang.Default(),
   249  				TempDir:      dir,
   250  				DefaultShell: "zoocar",
   251  				InitCmd:      "foobar",
   252  			},
   253  			want: fmt.Errorf("could not find init: command or path \"foobar\" not included in u-root build"),
   254  			validators: []itest.ArchiveValidator{
   255  				itest.IsEmpty{},
   256  			},
   257  		},
   258  		{
   259  			name: "init symlinked to absolute path",
   260  			opts: Opts{
   261  				Env:     golang.Default(),
   262  				TempDir: dir,
   263  				InitCmd: "/bin/systemd",
   264  			},
   265  			want: nil,
   266  			validators: []itest.ArchiveValidator{
   267  				itest.HasRecord{cpio.Symlink("init", "bin/systemd")},
   268  			},
   269  		},
   270  		{
   271  			name: "multi-mode archive",
   272  			opts: Opts{
   273  				Env:             golang.Default(),
   274  				TempDir:         dir,
   275  				ExtraFiles:      nil,
   276  				UseExistingInit: false,
   277  				InitCmd:         "init",
   278  				DefaultShell:    "ls",
   279  				Commands: []Commands{
   280  					{
   281  						Builder: builder.BusyBox,
   282  						Packages: []string{
   283  							"github.com/u-root/u-root/cmds/init",
   284  							"github.com/u-root/u-root/cmds/ls",
   285  						},
   286  					},
   287  					{
   288  						Builder: builder.Binary,
   289  						Packages: []string{
   290  							"github.com/u-root/u-root/cmds/cp",
   291  							"github.com/u-root/u-root/cmds/dd",
   292  						},
   293  					},
   294  					{
   295  						Builder: builder.Source,
   296  						Packages: []string{
   297  							"github.com/u-root/u-root/cmds/cat",
   298  							"github.com/u-root/u-root/cmds/chroot",
   299  							"github.com/u-root/u-root/cmds/installcommand",
   300  						},
   301  					},
   302  				},
   303  			},
   304  			want: nil,
   305  			validators: []itest.ArchiveValidator{
   306  				itest.HasRecord{cpio.Symlink("init", "bbin/init")},
   307  
   308  				// bb mode.
   309  				itest.HasFile{"bbin/bb"},
   310  				itest.HasRecord{cpio.Symlink("bbin/init", "bb")},
   311  				itest.HasRecord{cpio.Symlink("bbin/ls", "bb")},
   312  				itest.HasRecord{cpio.Symlink("bin/defaultsh", "../bbin/ls")},
   313  				itest.HasRecord{cpio.Symlink("bin/sh", "../bbin/ls")},
   314  
   315  				// binary mode.
   316  				itest.HasFile{"bin/cp"},
   317  				itest.HasFile{"bin/dd"},
   318  
   319  				// source mode.
   320  				itest.HasRecord{cpio.Symlink("buildbin/cat", "installcommand")},
   321  				itest.HasRecord{cpio.Symlink("buildbin/chroot", "installcommand")},
   322  				itest.HasFile{"buildbin/installcommand"},
   323  				itest.HasFile{"src/github.com/u-root/u-root/cmds/cat/cat.go"},
   324  				itest.HasFile{"src/github.com/u-root/u-root/cmds/chroot/chroot.go"},
   325  				itest.HasFile{"src/github.com/u-root/u-root/cmds/installcommand/installcommand.go"},
   326  			},
   327  		},
   328  	} {
   329  		t.Run(fmt.Sprintf("Test %d [%s]", i, tt.name), func(t *testing.T) {
   330  			archive := inMemArchive{cpio.InMemArchive()}
   331  			tt.opts.OutputFile = archive
   332  			// Compare error type or error string.
   333  			if err := CreateInitramfs(l, tt.opts); err != tt.want && (tt.want == nil || err.Error() != tt.want.Error()) {
   334  				t.Errorf("CreateInitramfs(%v) = %v, want %v", tt.opts, err, tt.want)
   335  			}
   336  
   337  			for _, v := range tt.validators {
   338  				if err := v.Validate(archive.Archive); err != nil {
   339  					t.Errorf("validator failed: %v / archive:\n%s", err, archive)
   340  				}
   341  			}
   342  		})
   343  	}
   344  }