github.com/TrenchBoot/u-root@v6.0.1-0.20200623220532-550e36da3258+incompatible/uroot_test.go (about)

     1  // Copyright 2015-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 main
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/sha256"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"testing"
    17  
    18  	"github.com/u-root/u-root/pkg/cpio"
    19  	"github.com/u-root/u-root/pkg/testutil"
    20  	itest "github.com/u-root/u-root/pkg/uroot/initramfs/test"
    21  )
    22  
    23  var twocmds = []string{
    24  	"github.com/u-root/u-root/cmds/core/ls",
    25  	"github.com/u-root/u-root/cmds/core/init",
    26  }
    27  
    28  var srcmds = []string{
    29  	"github.com/u-root/u-root/cmds/core/ls",
    30  	"github.com/u-root/u-root/cmds/core/init",
    31  	"github.com/u-root/u-root/cmds/core/installcommand",
    32  }
    33  
    34  type buildSourceValidator struct {
    35  	gopath string
    36  	goroot string
    37  	env    []string
    38  }
    39  
    40  func (b buildSourceValidator) Validate(a *cpio.Archive) error {
    41  	dir, err := ioutil.TempDir("", "u-root-source-")
    42  	if err != nil {
    43  		return err
    44  	}
    45  	defer os.RemoveAll(dir)
    46  
    47  	if err := os.Mkdir(filepath.Join(dir, "tmp"), 0755); err != nil {
    48  		return err
    49  	}
    50  
    51  	// Unpack into dir.
    52  	err = cpio.ForEachRecord(a.Reader(), func(r cpio.Record) error {
    53  		return cpio.CreateFileInRoot(r, dir, false)
    54  	})
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	goroot := filepath.Join(dir, b.goroot)
    60  	gopath := filepath.Join(dir, b.gopath)
    61  	// go build ./src/...
    62  	c := exec.Command(filepath.Join(goroot, "bin/go"), "build", filepath.Join(gopath, "src/..."))
    63  	c.Env = append(b.env,
    64  		fmt.Sprintf("GOPATH=%s", gopath),
    65  		fmt.Sprintf("GOCACHE=%s", filepath.Join(dir, "tmp")),
    66  		fmt.Sprintf("GOROOT=%s", goroot),
    67  		"CGO_ENABLED=0")
    68  	out, err := c.CombinedOutput()
    69  	if err != nil {
    70  		return fmt.Errorf("could not build go source %v; output\n%s", err, out)
    71  	}
    72  	return nil
    73  }
    74  
    75  func TestUrootCmdline(t *testing.T) {
    76  	samplef, err := ioutil.TempFile("", "u-root-sample-")
    77  	if err != nil {
    78  		t.Fatal(err)
    79  	}
    80  	samplef.Close()
    81  	defer os.RemoveAll(samplef.Name())
    82  
    83  	for _, tt := range []struct {
    84  		name       string
    85  		env        []string
    86  		args       []string
    87  		err        error
    88  		validators []itest.ArchiveValidator
    89  	}{
    90  		{
    91  			name: "include one extra file",
    92  			args: []string{"-nocmd", "-files=/bin/bash"},
    93  			err:  nil,
    94  			validators: []itest.ArchiveValidator{
    95  				itest.HasFile{"bin/bash"},
    96  			},
    97  		},
    98  		{
    99  			name: "uinitcmd",
   100  			args: []string{"-build=bb", "-uinitcmd=echo foobar fuzz", "-defaultsh=", "./cmds/core/init", "./cmds/core/echo"},
   101  			err:  nil,
   102  			validators: []itest.ArchiveValidator{
   103  				itest.HasRecord{cpio.Symlink("bin/uinit", "../bbin/echo")},
   104  				itest.HasContent{
   105  					Path:    "etc/uinit.flags",
   106  					Content: "\"foobar\"\n\"fuzz\"",
   107  				},
   108  			},
   109  		},
   110  		{
   111  			name: "fix usage of an absolute path",
   112  			args: []string{"-nocmd", "-files=/bin:/bin"},
   113  			err:  nil,
   114  			validators: []itest.ArchiveValidator{
   115  				itest.HasFile{"bin/bash"},
   116  			},
   117  		},
   118  		{
   119  			name: "include multiple extra files",
   120  			args: []string{"-nocmd", "-files=/bin/bash", "-files=/bin/ls", fmt.Sprintf("-files=%s", samplef.Name())},
   121  			validators: []itest.ArchiveValidator{
   122  				itest.HasFile{"bin/bash"},
   123  				itest.HasFile{"bin/ls"},
   124  				itest.HasFile{samplef.Name()},
   125  			},
   126  		},
   127  		{
   128  			name: "include one extra file with rename",
   129  			args: []string{"-nocmd", "-files=/bin/bash:bin/bush"},
   130  			validators: []itest.ArchiveValidator{
   131  				itest.HasFile{"bin/bush"},
   132  			},
   133  		},
   134  		{
   135  			name: "hosted source mode",
   136  			args: append([]string{"-build=source", "-base=/dev/null", "-defaultsh=", "-initcmd="}, srcmds...),
   137  		},
   138  		{
   139  			name: "hosted bb mode",
   140  			args: append([]string{"-build=bb", "-base=/dev/null", "-defaultsh=", "-initcmd="}, twocmds...),
   141  		},
   142  		{
   143  			name: "AMD64 bb build",
   144  			env:  []string{"GOARCH=amd64"},
   145  			args: []string{"-build=bb", "all"},
   146  		},
   147  		{
   148  			name: "AMD64 source build",
   149  			env:  []string{"GOARCH=amd64"},
   150  			args: []string{"-build=source", "all"},
   151  			validators: []itest.ArchiveValidator{
   152  				buildSourceValidator{
   153  					goroot: "/go",
   154  					gopath: ".",
   155  					env:    []string{"GOARCH=amd64"},
   156  				},
   157  			},
   158  		},
   159  		{
   160  			name: "MIPS bb build",
   161  			env:  []string{"GOARCH=mips"},
   162  			args: []string{"-build=bb", "all"},
   163  		},
   164  		{
   165  			name: "MIPSLE bb build",
   166  			env:  []string{"GOARCH=mipsle"},
   167  			args: []string{"-build=bb", "all"},
   168  		},
   169  		{
   170  			name: "MIPS64 bb build",
   171  			env:  []string{"GOARCH=mips64"},
   172  			args: []string{"-build=bb", "all"},
   173  		},
   174  		{
   175  			name: "MIPS64LE bb build",
   176  			env:  []string{"GOARCH=mips64le"},
   177  			args: []string{"-build=bb", "all"},
   178  		},
   179  		{
   180  			name: "ARM7 bb build",
   181  			env:  []string{"GOARCH=arm", "GOARM=7"},
   182  			args: []string{"-build=bb", "all"},
   183  		},
   184  		{
   185  			name: "ARM64 bb build",
   186  			env:  []string{"GOARCH=arm64"},
   187  			args: []string{"-build=bb", "all"},
   188  		},
   189  		{
   190  			name: "386 (32 bit) bb build",
   191  			env:  []string{"GOARCH=386"},
   192  			args: []string{"-build=bb", "all"},
   193  		},
   194  		{
   195  			name: "Power 64bit bb build",
   196  			env:  []string{"GOARCH=ppc64le"},
   197  			args: []string{"-build=bb", "all"},
   198  		},
   199  	} {
   200  		t.Run(tt.name, func(t *testing.T) {
   201  			delFiles := true
   202  			f, sum1 := buildIt(t, tt.args, tt.env, tt.err)
   203  			defer func() {
   204  				if delFiles {
   205  					os.RemoveAll(f.Name())
   206  				}
   207  			}()
   208  
   209  			a, err := itest.ReadArchive(f.Name())
   210  			if err != nil {
   211  				t.Fatal(err)
   212  			}
   213  
   214  			for _, v := range tt.validators {
   215  				if err := v.Validate(a); err != nil {
   216  					t.Errorf("validator failed: %v / archive:\n%s", err, a)
   217  				}
   218  			}
   219  
   220  			f2, sum2 := buildIt(t, tt.args, tt.env, tt.err)
   221  			defer func() {
   222  				if delFiles {
   223  					os.RemoveAll(f2.Name())
   224  				}
   225  			}()
   226  			if !bytes.Equal(sum1, sum2) {
   227  				delFiles = false
   228  				t.Errorf("not reproducible, hashes don't match")
   229  				t.Errorf("env: %v args: %v", tt.env, tt.args)
   230  				t.Errorf("file1: %v file2: %v", f.Name(), f2.Name())
   231  			}
   232  		})
   233  	}
   234  }
   235  
   236  func buildIt(t *testing.T, args, env []string, want error) (*os.File, []byte) {
   237  	f, err := ioutil.TempFile("", "u-root-")
   238  	if err != nil {
   239  		t.Fatal(err)
   240  	}
   241  
   242  	arg := append([]string{"-o", f.Name()}, args...)
   243  	c := testutil.Command(t, arg...)
   244  	t.Logf("Commandline: %v", arg)
   245  	c.Env = append(c.Env, env...)
   246  	if out, err := c.CombinedOutput(); err != want {
   247  		t.Fatalf("Error: %v\nOutput:\n%s", err, out)
   248  	} else if err != nil {
   249  		h1 := sha256.New()
   250  		if _, err := io.Copy(h1, f); err != nil {
   251  			t.Fatal()
   252  		}
   253  		return f, h1.Sum(nil)
   254  	}
   255  	return f, nil
   256  }
   257  
   258  func TestMain(m *testing.M) {
   259  	testutil.Run(m, main)
   260  }