github.com/shaardie/u-root@v4.0.1-0.20190127173353-f24a1c26aa2e+incompatible/integration/gotest_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 integration 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path" 13 "path/filepath" 14 "regexp" 15 "sort" 16 "strings" 17 "testing" 18 "time" 19 ) 20 21 // testPkgs returns a slice of tests to run. 22 func testPkgs(t *testing.T) []string { 23 // Packages which do not contain tests (or do not contain tests for the 24 // build target) will still compile a test binary which vacuously pass. 25 cmd := exec.Command("go", "list", 26 "github.com/u-root/u-root/cmds/...", 27 // TODO: only running tests in cmds because tests in pkg have 28 // duplicate names which confuses the test runner. This should 29 // get fixed. 30 // "github.com/u-root/u-root/xcmds/...", 31 // "github.com/u-root/u-root/pkg/...", 32 ) 33 cmd.Env = append(os.Environ(), "GOARCH="+TestArch()) 34 out, err := cmd.CombinedOutput() 35 if err != nil { 36 t.Fatal(err) 37 } 38 pkgs := strings.Fields(strings.TrimSpace(string(out))) 39 40 // TODO: Some tests do not run properly in QEMU at the moment. They are 41 // blacklisted. These tests fail for mostly two reasons: 42 // 1. either it requires networking (not enabled in the kernel) 43 // 2. or it depends on some test files (for example /bin/sleep) 44 blacklist := []string{ 45 "github.com/u-root/u-root/cmds/bzimage", 46 "github.com/u-root/u-root/cmds/cmp", 47 "github.com/u-root/u-root/cmds/dd", 48 "github.com/u-root/u-root/cmds/dhclient", 49 "github.com/u-root/u-root/cmds/elvish/eval", 50 "github.com/u-root/u-root/cmds/fmap", 51 "github.com/u-root/u-root/cmds/gpt", 52 "github.com/u-root/u-root/cmds/kill", 53 "github.com/u-root/u-root/cmds/mount", 54 "github.com/u-root/u-root/cmds/tail", 55 "github.com/u-root/u-root/cmds/wget", 56 "github.com/u-root/u-root/cmds/which", 57 "github.com/u-root/u-root/cmds/wifi", 58 } 59 for i := 0; i < len(pkgs); i++ { 60 for _, b := range blacklist { 61 if pkgs[i] == b { 62 pkgs = append(pkgs[:i], pkgs[i+1:]...) 63 } 64 } 65 } 66 67 return pkgs 68 } 69 70 // TestGoTest effectively runs "go test ./..." inside a QEMU instance. The 71 // tests run as root and can do all sorts of things not possible otherwise. 72 func TestGoTest(t *testing.T) { 73 SkipWithoutQEMU(t) 74 75 // TODO: support arm 76 if TestArch() != "amd64" { 77 t.Skipf("test not supported on %s", TestArch()) 78 } 79 80 // Create a temporary directory. 81 tmpDir, err := ioutil.TempDir("", "uroot-integration") 82 if err != nil { 83 t.Fatal(err) 84 } 85 86 // Statically build tests and add them to the temporary directory. 87 pkgs := testPkgs(t) 88 tests := []string{} 89 os.Setenv("CGO_ENABLED", "0") 90 testDir := filepath.Join(tmpDir, "tests") 91 for _, pkg := range pkgs { 92 testFile := filepath.Join(testDir, path.Base(pkg)) 93 cmd := exec.Command("go", "test", "-ldflags", "-s -w", "-c", pkg, "-o", testFile) 94 if err := cmd.Run(); err != nil { 95 t.Fatalf("could not build %s: %v", pkg, err) 96 } 97 98 // When a package does not contain any tests, the test 99 // executable is not generated, so it is not included in the 100 // `tests` list. 101 if _, err := os.Stat(testFile); !os.IsNotExist(err) { 102 tests = append(tests, pkg) 103 } 104 } 105 106 // Create the CPIO and start QEMU. 107 q, cleanup := QEMUTest(t, &Options{ 108 Cmds: []string{ 109 "github.com/u-root/u-root/integration/testcmd/gotest/uinit", 110 "github.com/u-root/u-root/cmds/init", 111 // Used by gotest/uinit. 112 "github.com/u-root/u-root/cmds/mkdir", 113 "github.com/u-root/u-root/cmds/mount", 114 // Used by an elvish test. 115 "github.com/u-root/u-root/cmds/ls", 116 }, 117 TmpDir: tmpDir, 118 }) 119 defer cleanup() 120 121 // Tests are run and checked in sorted order. 122 bases := []string{} 123 for _, test := range tests { 124 bases = append(bases, path.Base(test)) 125 } 126 sort.Strings(bases) 127 128 // Check that the test runner is running inside QEMU. 129 headerMsg := fmt.Sprintf("TAP: 1..%d", len(bases)) 130 if err := q.ExpectTimeout(headerMsg, 30*time.Second); err != nil { 131 t.Fatalf("cannot communicate with test runner: %v", err) 132 } 133 t.Log(headerMsg) 134 135 // Check that each test passed. 136 for i, base := range bases { 137 runMsg := fmt.Sprintf("TAP: # running %d - %s", i, base) 138 passMsg := fmt.Sprintf("TAP: ok %d - %s", i, base) 139 failMsg := fmt.Sprintf("TAP: not ok %d - %s", i, base) 140 passOrFailMsg := regexp.MustCompile(fmt.Sprintf("TAP: (not )?ok %d - %s", i, base)) 141 142 t.Log(runMsg) 143 str, err := q.ExpectRETimeout(passOrFailMsg, 30*time.Second) 144 if err != nil { 145 // If we can neither find the "ok" nor the "not ok" message, the 146 // test runner inside QEMU is misbehaving and we fatal early 147 // instead of wasting time. 148 t.Logf(failMsg) 149 t.Fatal("TAP: Bail out! QEMU test runner stopped printing.") 150 } 151 152 if strings.Contains(str, passMsg) { 153 t.Log(passMsg) 154 } else { 155 t.Error(failMsg) 156 } 157 } 158 }