github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/pkg/vmtest/gotest.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 vmtest 6 7 import ( 8 "fmt" 9 "io" 10 "io/ioutil" 11 "os" 12 "os/exec" 13 "path" 14 "path/filepath" 15 "testing" 16 17 "github.com/u-root/u-root/pkg/golang" 18 "github.com/u-root/u-root/pkg/uio" 19 "github.com/u-root/u-root/pkg/uroot" 20 "github.com/u-root/u-root/pkg/vmtest/internal/json2test" 21 ) 22 23 // GolangTest compiles the unit tests found in pkgs and runs them in a QEMU VM. 24 func GolangTest(t *testing.T, pkgs []string, o *Options) { 25 SkipWithoutQEMU(t) 26 // TODO: support arm 27 if TestArch() != "amd64" { 28 t.Skipf("test not supported on %s", TestArch()) 29 } 30 31 if o == nil { 32 o = &Options{} 33 } 34 35 // Create a temporary directory. 36 if len(o.BuildOpts.TempDir) == 0 { 37 tmpDir, err := ioutil.TempDir("", "uroot-integration") 38 if err != nil { 39 t.Fatal(err) 40 } 41 o.BuildOpts.TempDir = tmpDir 42 } 43 44 env := golang.Default() 45 env.CgoEnabled = false 46 env.GOARCH = TestArch() 47 o.BuildOpts.Env = env 48 49 // Statically build tests and add them to the temporary directory. 50 var tests []string 51 os.Setenv("CGO_ENABLED", "0") 52 testDir := filepath.Join(o.BuildOpts.TempDir, "tests") 53 for _, pkg := range pkgs { 54 pkgDir := filepath.Join(testDir, pkg) 55 if err := os.MkdirAll(pkgDir, 0755); err != nil { 56 t.Fatal(err) 57 } 58 59 testFile := filepath.Join(pkgDir, fmt.Sprintf("%s.test", path.Base(pkg))) 60 61 cmd := exec.Command("go", "test", 62 "-ldflags", "-s -w", 63 "-c", pkg, 64 "-o", testFile, 65 ) 66 if stderr, err := cmd.CombinedOutput(); err != nil { 67 t.Fatalf("could not build %s: %v\n%s", pkg, err, string(stderr)) 68 } 69 70 // When a package does not contain any tests, the test 71 // executable is not generated, so it is not included in the 72 // `tests` list. 73 if _, err := os.Stat(testFile); !os.IsNotExist(err) { 74 tests = append(tests, pkg) 75 76 p, err := o.BuildOpts.Env.FindOne(pkg) 77 if err != nil { 78 t.Fatal(err) 79 } 80 // Optimistically copy any files in the pkg's 81 // directory, in case e.g. a testdata dir is there. 82 if err := copyRelativeFiles(p.Dir, filepath.Join(testDir, pkg)); err != nil { 83 t.Fatal(err) 84 } 85 } 86 } 87 88 // Create the CPIO and start QEMU. 89 o.BuildOpts.AddCommands(uroot.BinaryCmds("cmd/test2json")...) 90 o.BuildOpts.AddBusyBoxCommands( 91 "github.com/u-root/u-root/integration/testcmd/gotest/uinit", 92 "github.com/u-root/u-root/cmds/core/init", 93 ) 94 95 tc := json2test.NewTestCollector() 96 serial := []io.Writer{ 97 // Collect JSON test events in tc. 98 json2test.EventParser(tc), 99 // Write non-JSON output to log. 100 JSONLessTestLineWriter(t, "serial"), 101 } 102 if o.QEMUOpts.SerialOutput != nil { 103 serial = append(serial, o.QEMUOpts.SerialOutput) 104 } 105 o.QEMUOpts.SerialOutput = uio.MultiWriteCloser(serial...) 106 107 q, cleanup := QEMUTest(t, o) 108 defer cleanup() 109 110 if err := q.Expect("GoTest Done"); err != nil { 111 t.Errorf("Waiting for GoTest Done: %v", err) 112 } 113 114 // TODO: check that tc.Tests == tests 115 for pkg, test := range tc.Tests { 116 switch test.State { 117 case json2test.StateFail: 118 t.Errorf("Test %v failed:\n%v", pkg, test.FullOutput) 119 case json2test.StateSkip: 120 t.Logf("Test %v skipped", pkg) 121 case json2test.StatePass: 122 // Nothing. 123 default: 124 t.Errorf("Test %v left in state %v:\n%v", pkg, test.State, test.FullOutput) 125 } 126 } 127 } 128 129 func copyRelativeFiles(src string, dst string) error { 130 return filepath.Walk(src, func(path string, fi os.FileInfo, err error) error { 131 if err != nil { 132 return err 133 } 134 135 rel, err := filepath.Rel(src, path) 136 if err != nil { 137 return err 138 } 139 140 if fi.Mode().IsDir() { 141 return os.MkdirAll(filepath.Join(dst, rel), fi.Mode().Perm()) 142 } else if fi.Mode().IsRegular() { 143 srcf, err := os.Open(path) 144 if err != nil { 145 return err 146 } 147 defer srcf.Close() 148 dstf, err := os.Create(filepath.Join(dst, rel)) 149 if err != nil { 150 return err 151 } 152 defer dstf.Close() 153 _, err = io.Copy(dstf, srcf) 154 return err 155 } 156 return nil 157 }) 158 }