github.com/shaardie/u-root@v4.0.1-0.20190127173353-f24a1c26aa2e+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/ls",
    25  	"github.com/u-root/u-root/cmds/init",
    26  }
    27  
    28  var srcmds = []string{
    29  	"github.com/u-root/u-root/cmds/ls",
    30  	"github.com/u-root/u-root/cmds/init",
    31  	"github.com/u-root/u-root/cmds/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  	// Unpack into dir.
    48  	err = cpio.ForEachRecord(a.Reader(), func(r cpio.Record) error {
    49  		return cpio.CreateFileInRoot(r, dir, false)
    50  	})
    51  	if err != nil {
    52  		return err
    53  	}
    54  
    55  	goroot := filepath.Join(dir, b.goroot)
    56  	gopath := filepath.Join(dir, b.gopath)
    57  	// go build ./src/...
    58  	c := exec.Command(filepath.Join(goroot, "bin/go"), "build", filepath.Join(gopath, "src/..."))
    59  	c.Env = append(b.env,
    60  		fmt.Sprintf("GOPATH=%s", gopath),
    61  		fmt.Sprintf("GOROOT=%s", goroot))
    62  	out, err := c.CombinedOutput()
    63  	if err != nil {
    64  		return fmt.Errorf("could not build go source %v; output\n%s", err, out)
    65  	}
    66  	return nil
    67  }
    68  
    69  func TestUrootCmdline(t *testing.T) {
    70  	samplef, err := ioutil.TempFile("", "u-root-sample-")
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	samplef.Close()
    75  	defer os.RemoveAll(samplef.Name())
    76  
    77  	for _, tt := range []struct {
    78  		name       string
    79  		env        []string
    80  		args       []string
    81  		err        error
    82  		validators []itest.ArchiveValidator
    83  	}{
    84  		{
    85  			name: "include one extra file",
    86  			args: []string{"-nocmd", "-files=/bin/bash"},
    87  			err:  nil,
    88  			validators: []itest.ArchiveValidator{
    89  				itest.HasFile{"bin/bash"},
    90  			},
    91  		},
    92  		{
    93  			name: "include multiple extra files",
    94  			args: []string{"-nocmd", "-files=/bin/bash", "-files=/bin/ls", fmt.Sprintf("-files=%s", samplef.Name())},
    95  			validators: []itest.ArchiveValidator{
    96  				itest.HasFile{"bin/bash"},
    97  				itest.HasFile{"bin/ls"},
    98  				itest.HasFile{samplef.Name()},
    99  			},
   100  		},
   101  		{
   102  			name: "include one extra file with rename",
   103  			args: []string{"-nocmd", "-files=/bin/bash:bin/bush"},
   104  			validators: []itest.ArchiveValidator{
   105  				itest.HasFile{"bin/bush"},
   106  			},
   107  		},
   108  		{
   109  			name: "hosted source mode",
   110  			args: append([]string{"-build=source", "-base=/dev/null", "-defaultsh=", "-initcmd="}, srcmds...),
   111  		},
   112  		{
   113  			name: "hosted bb mode",
   114  			args: append([]string{"-build=bb", "-base=/dev/null", "-defaultsh=", "-initcmd="}, twocmds...),
   115  		},
   116  		{
   117  			name: "AMD64 bb build",
   118  			env:  []string{"GOARCH=amd64"},
   119  			args: []string{"-build=bb"},
   120  		},
   121  		{
   122  			name: "AMD64 source build",
   123  			env:  []string{"GOARCH=amd64"},
   124  			args: []string{"-build=source"},
   125  			validators: []itest.ArchiveValidator{
   126  				buildSourceValidator{
   127  					goroot: "/go",
   128  					gopath: ".",
   129  					env:    []string{"GOARCH=amd64"},
   130  				},
   131  			},
   132  		},
   133  		{
   134  			name: "ARM7 bb build",
   135  			env:  []string{"GOARCH=arm", "GOARM=7"},
   136  			args: []string{"-build=bb"},
   137  		},
   138  		{
   139  			name: "ARM64 bb build",
   140  			env:  []string{"GOARCH=arm64"},
   141  			args: []string{"-build=bb"},
   142  		},
   143  		{
   144  			name: "Power 64bit bb build",
   145  			env:  []string{"GOARCH=ppc64le"},
   146  			args: []string{"-build=bb"},
   147  		},
   148  	} {
   149  		t.Run(tt.name, func(t *testing.T) {
   150  			delFiles := true
   151  			f, sum1 := buildIt(t, tt.args, tt.env, tt.err)
   152  			defer func() {
   153  				if delFiles {
   154  					os.RemoveAll(f.Name())
   155  				}
   156  			}()
   157  
   158  			a, err := itest.ReadArchive(f.Name())
   159  			if err != nil {
   160  				t.Fatal(err)
   161  			}
   162  
   163  			for _, v := range tt.validators {
   164  				if err := v.Validate(a); err != nil {
   165  					t.Errorf("validator failed: %v / archive:\n%s", err, a)
   166  				}
   167  			}
   168  
   169  			f2, sum2 := buildIt(t, tt.args, tt.env, tt.err)
   170  			defer func() {
   171  				if delFiles {
   172  					os.RemoveAll(f2.Name())
   173  				}
   174  			}()
   175  			if !bytes.Equal(sum1, sum2) {
   176  				delFiles = false
   177  				t.Errorf("not reproducible, hashes don't match")
   178  				t.Errorf("env: %v args: %v", tt.env, tt.args)
   179  				t.Errorf("file1: %v file2: %v", f.Name(), f2.Name())
   180  			}
   181  		})
   182  	}
   183  }
   184  
   185  func buildIt(t *testing.T, args, env []string, want error) (*os.File, []byte) {
   186  	f, err := ioutil.TempFile("", "u-root-")
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  
   191  	arg := append([]string{"-o", f.Name()}, args...)
   192  	c := testutil.Command(t, arg...)
   193  	t.Logf("Commandline: %v", arg)
   194  	c.Env = append(c.Env, env...)
   195  	if out, err := c.CombinedOutput(); err != want {
   196  		t.Fatalf("Error: %v\nOutput:\n%s", err, out)
   197  	} else if err != nil {
   198  		h1 := sha256.New()
   199  		if _, err := io.Copy(h1, f); err != nil {
   200  			t.Fatal()
   201  		}
   202  		return f, h1.Sum(nil)
   203  	}
   204  	return f, nil
   205  }
   206  
   207  func TestMain(m *testing.M) {
   208  	testutil.Run(m, main)
   209  }