github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/integration/testcmd/gotest/uinit/gotest.go (about) 1 // Copyright 2021 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 "context" 9 "flag" 10 "fmt" 11 "io" 12 "log" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "strings" 17 "time" 18 19 "github.com/mvdan/u-root-coreutils/integration/testcmd/common" 20 "golang.org/x/sys/unix" 21 ) 22 23 const individualTestTimeout = 25 * time.Second 24 25 var coverProfile = flag.String("coverprofile", "", "Filename to write coverage data to") 26 27 func walkTests(testRoot string, fn func(string, string)) error { 28 return filepath.Walk(testRoot, func(path string, info os.FileInfo, err error) error { 29 if !info.Mode().IsRegular() || !strings.HasSuffix(path, ".test") || err != nil { 30 return nil 31 } 32 t2, err := filepath.Rel(testRoot, path) 33 if err != nil { 34 return err 35 } 36 pkgName := filepath.Dir(t2) 37 38 fn(path, pkgName) 39 return nil 40 }) 41 } 42 43 // AppendFile takes two filepaths and concatenates the files at those. 44 func AppendFile(srcFile, targetFile string) error { 45 cov, err := os.Open(srcFile) 46 if err != nil { 47 return err 48 } 49 defer cov.Close() 50 51 out, err := os.OpenFile(targetFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644) 52 if err != nil { 53 return err 54 } 55 56 if _, err := io.Copy(out, cov); err != nil { 57 if err := out.Close(); err != nil { 58 return err 59 } 60 return fmt.Errorf("error appending %s to %s: %v", srcFile, targetFile, err) 61 } 62 63 return out.Close() 64 } 65 66 // runTest mounts a vfat or 9pfs volume and runs the tests within. 67 func runTest() error { 68 flag.Parse() 69 70 if err := os.MkdirAll("/testdata", 0755); err != nil { 71 log.Fatalf("Couldn't create testdata directory: %v", err) 72 } 73 74 cleanup, err := common.MountSharedDir() 75 if err != nil { 76 return err 77 } 78 defer cleanup() 79 defer common.CollectKernelCoverage() 80 81 walkTests("/testdata/tests", func(path, pkgName string) { 82 // Send the kill signal with a 500ms grace period. 83 ctx, cancel := context.WithTimeout(context.Background(), individualTestTimeout+500*time.Millisecond) 84 defer cancel() 85 86 r, w, err := os.Pipe() 87 if err != nil { 88 log.Printf("Failed to get pipe: %v", err) 89 return 90 } 91 92 args := []string{"-test.v", "-test.bench=.", "-test.run=."} 93 coverFile := filepath.Join(filepath.Dir(path), "coverage.txt") 94 if len(*coverProfile) > 0 { 95 args = append(args, "-test.coverprofile", coverFile) 96 } 97 98 cmd := exec.CommandContext(ctx, path, args...) 99 cmd.Stdin, cmd.Stderr = os.Stdin, os.Stderr 100 101 // Write to stdout for humans, write to w for the JSON converter. 102 // 103 // The test collector will gobble up JSON for statistics, and 104 // print non-JSON for humans to consume. 105 cmd.Stdout = io.MultiWriter(os.Stdout, w) 106 107 // Start test in its own dir so that testdata is available as a 108 // relative directory. 109 cmd.Dir = filepath.Dir(path) 110 if err := cmd.Start(); err != nil { 111 log.Printf("Failed to start %q: %v", path, err) 112 return 113 } 114 115 // The test2json is not run with a context as it does not 116 // block. If we cancelled test2json with the same context as 117 // the test, we may lose some of the last few lines. 118 j := exec.Command("test2json", "-t", "-p", pkgName) 119 j.Stdin = r 120 j.Stdout, cmd.Stderr = os.Stdout, os.Stderr 121 if err := j.Start(); err != nil { 122 log.Printf("Failed to start test2json: %v", err) 123 return 124 } 125 126 if err := cmd.Wait(); err != nil { 127 // Log for processing by test2json. 128 fmt.Fprintf(w, "Error: test for %q exited early: %v", pkgName, err) 129 } 130 131 // Close the pipe so test2json will quit. 132 if err := w.Close(); err != nil { 133 log.Printf("Failed to close pipe: %v", err) 134 } 135 if err := j.Wait(); err != nil { 136 log.Printf("Failed to stop test2json: %v", err) 137 } 138 139 if err := AppendFile(coverFile, *coverProfile); err != nil { 140 log.Printf("Could not append to cover file: %v", err) 141 } 142 }) 143 return nil 144 } 145 146 func main() { 147 if err := runTest(); err != nil { 148 log.Printf("Tests failed: %v", err) 149 } else { 150 // The test infra is expecting this exact print. 151 log.Print("TESTS PASSED MARKER") 152 } 153 154 if err := unix.Reboot(unix.LINUX_REBOOT_CMD_POWER_OFF); err != nil { 155 log.Fatalf("Failed to reboot: %v", err) 156 } 157 }