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