xref: /aosp_15_r20/external/boringssl/src/util/all_tests.go (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1*8fb009dcSAndroid Build Coastguard Worker// Copyright (c) 2015, Google Inc.
2*8fb009dcSAndroid Build Coastguard Worker//
3*8fb009dcSAndroid Build Coastguard Worker// Permission to use, copy, modify, and/or distribute this software for any
4*8fb009dcSAndroid Build Coastguard Worker// purpose with or without fee is hereby granted, provided that the above
5*8fb009dcSAndroid Build Coastguard Worker// copyright notice and this permission notice appear in all copies.
6*8fb009dcSAndroid Build Coastguard Worker//
7*8fb009dcSAndroid Build Coastguard Worker// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8*8fb009dcSAndroid Build Coastguard Worker// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9*8fb009dcSAndroid Build Coastguard Worker// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10*8fb009dcSAndroid Build Coastguard Worker// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11*8fb009dcSAndroid Build Coastguard Worker// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12*8fb009dcSAndroid Build Coastguard Worker// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13*8fb009dcSAndroid Build Coastguard Worker// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14*8fb009dcSAndroid Build Coastguard Worker
15*8fb009dcSAndroid Build Coastguard Worker//go:build ignore
16*8fb009dcSAndroid Build Coastguard Worker
17*8fb009dcSAndroid Build Coastguard Workerpackage main
18*8fb009dcSAndroid Build Coastguard Worker
19*8fb009dcSAndroid Build Coastguard Workerimport (
20*8fb009dcSAndroid Build Coastguard Worker	"bytes"
21*8fb009dcSAndroid Build Coastguard Worker	"errors"
22*8fb009dcSAndroid Build Coastguard Worker	"flag"
23*8fb009dcSAndroid Build Coastguard Worker	"fmt"
24*8fb009dcSAndroid Build Coastguard Worker	"os"
25*8fb009dcSAndroid Build Coastguard Worker	"os/exec"
26*8fb009dcSAndroid Build Coastguard Worker	"path"
27*8fb009dcSAndroid Build Coastguard Worker	"runtime"
28*8fb009dcSAndroid Build Coastguard Worker	"strconv"
29*8fb009dcSAndroid Build Coastguard Worker	"strings"
30*8fb009dcSAndroid Build Coastguard Worker	"sync"
31*8fb009dcSAndroid Build Coastguard Worker	"syscall"
32*8fb009dcSAndroid Build Coastguard Worker
33*8fb009dcSAndroid Build Coastguard Worker	"boringssl.googlesource.com/boringssl/util/testconfig"
34*8fb009dcSAndroid Build Coastguard Worker	"boringssl.googlesource.com/boringssl/util/testresult"
35*8fb009dcSAndroid Build Coastguard Worker)
36*8fb009dcSAndroid Build Coastguard Worker
37*8fb009dcSAndroid Build Coastguard Worker// TODO(davidben): Link tests with the malloc shim and port -malloc-test to this runner.
38*8fb009dcSAndroid Build Coastguard Worker
39*8fb009dcSAndroid Build Coastguard Workervar (
40*8fb009dcSAndroid Build Coastguard Worker	useValgrind     = flag.Bool("valgrind", false, "If true, run code under valgrind")
41*8fb009dcSAndroid Build Coastguard Worker	useCallgrind    = flag.Bool("callgrind", false, "If true, run code under valgrind to generate callgrind traces.")
42*8fb009dcSAndroid Build Coastguard Worker	useGDB          = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb")
43*8fb009dcSAndroid Build Coastguard Worker	useSDE          = flag.Bool("sde", false, "If true, run BoringSSL code under Intel's SDE for each supported chip")
44*8fb009dcSAndroid Build Coastguard Worker	sdePath         = flag.String("sde-path", "sde", "The path to find the sde binary.")
45*8fb009dcSAndroid Build Coastguard Worker	buildDir        = flag.String("build-dir", "build", "The build directory to run the tests from.")
46*8fb009dcSAndroid Build Coastguard Worker	numWorkers      = flag.Int("num-workers", runtime.NumCPU(), "Runs the given number of workers when testing.")
47*8fb009dcSAndroid Build Coastguard Worker	jsonOutput      = flag.String("json-output", "", "The file to output JSON results to.")
48*8fb009dcSAndroid Build Coastguard Worker	mallocTest      = flag.Int64("malloc-test", -1, "If non-negative, run each test with each malloc in turn failing from the given number onwards.")
49*8fb009dcSAndroid Build Coastguard Worker	mallocTestDebug = flag.Bool("malloc-test-debug", false, "If true, ask each test to abort rather than fail a malloc. This can be used with a specific value for --malloc-test to identity the malloc failing that is causing problems.")
50*8fb009dcSAndroid Build Coastguard Worker	simulateARMCPUs = flag.Bool("simulate-arm-cpus", simulateARMCPUsDefault(), "If true, runs tests simulating different ARM CPUs.")
51*8fb009dcSAndroid Build Coastguard Worker	qemuBinary      = flag.String("qemu", "", "Optional, absolute path to a binary location for QEMU runtime.")
52*8fb009dcSAndroid Build Coastguard Worker)
53*8fb009dcSAndroid Build Coastguard Worker
54*8fb009dcSAndroid Build Coastguard Workerfunc simulateARMCPUsDefault() bool {
55*8fb009dcSAndroid Build Coastguard Worker	return (runtime.GOOS == "linux" || runtime.GOOS == "android") && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
56*8fb009dcSAndroid Build Coastguard Worker}
57*8fb009dcSAndroid Build Coastguard Worker
58*8fb009dcSAndroid Build Coastguard Workertype test struct {
59*8fb009dcSAndroid Build Coastguard Worker	testconfig.Test
60*8fb009dcSAndroid Build Coastguard Worker
61*8fb009dcSAndroid Build Coastguard Worker	shard, numShards int
62*8fb009dcSAndroid Build Coastguard Worker	// cpu, if not empty, contains a code to simulate. For SDE, run `sde64
63*8fb009dcSAndroid Build Coastguard Worker	// -help` to get a list of these codes. For ARM, see gtest_main.cc for
64*8fb009dcSAndroid Build Coastguard Worker	// the supported values.
65*8fb009dcSAndroid Build Coastguard Worker	cpu string
66*8fb009dcSAndroid Build Coastguard Worker}
67*8fb009dcSAndroid Build Coastguard Worker
68*8fb009dcSAndroid Build Coastguard Workertype result struct {
69*8fb009dcSAndroid Build Coastguard Worker	Test   test
70*8fb009dcSAndroid Build Coastguard Worker	Passed bool
71*8fb009dcSAndroid Build Coastguard Worker	Error  error
72*8fb009dcSAndroid Build Coastguard Worker}
73*8fb009dcSAndroid Build Coastguard Worker
74*8fb009dcSAndroid Build Coastguard Worker// sdeCPUs contains a list of CPU code that we run all tests under when *useSDE
75*8fb009dcSAndroid Build Coastguard Worker// is true.
76*8fb009dcSAndroid Build Coastguard Workervar sdeCPUs = []string{
77*8fb009dcSAndroid Build Coastguard Worker	"p4p", // Pentium4 Prescott
78*8fb009dcSAndroid Build Coastguard Worker	"mrm", // Merom
79*8fb009dcSAndroid Build Coastguard Worker	"pnr", // Penryn
80*8fb009dcSAndroid Build Coastguard Worker	"nhm", // Nehalem
81*8fb009dcSAndroid Build Coastguard Worker	"wsm", // Westmere
82*8fb009dcSAndroid Build Coastguard Worker	"snb", // Sandy Bridge
83*8fb009dcSAndroid Build Coastguard Worker	"ivb", // Ivy Bridge
84*8fb009dcSAndroid Build Coastguard Worker	"hsw", // Haswell
85*8fb009dcSAndroid Build Coastguard Worker	"bdw", // Broadwell
86*8fb009dcSAndroid Build Coastguard Worker	"slt", // Saltwell
87*8fb009dcSAndroid Build Coastguard Worker	"slm", // Silvermont
88*8fb009dcSAndroid Build Coastguard Worker	"glm", // Goldmont
89*8fb009dcSAndroid Build Coastguard Worker	"glp", // Goldmont Plus
90*8fb009dcSAndroid Build Coastguard Worker	"tnt", // Tremont
91*8fb009dcSAndroid Build Coastguard Worker	"skl", // Skylake
92*8fb009dcSAndroid Build Coastguard Worker	"cnl", // Cannon Lake
93*8fb009dcSAndroid Build Coastguard Worker	"icl", // Ice Lake
94*8fb009dcSAndroid Build Coastguard Worker	"skx", // Skylake server
95*8fb009dcSAndroid Build Coastguard Worker	"clx", // Cascade Lake
96*8fb009dcSAndroid Build Coastguard Worker	"cpx", // Cooper Lake
97*8fb009dcSAndroid Build Coastguard Worker	"icx", // Ice Lake server
98*8fb009dcSAndroid Build Coastguard Worker	"tgl", // Tiger Lake
99*8fb009dcSAndroid Build Coastguard Worker}
100*8fb009dcSAndroid Build Coastguard Worker
101*8fb009dcSAndroid Build Coastguard Workervar armCPUs = []string{
102*8fb009dcSAndroid Build Coastguard Worker	"none",   // No support for any ARM extensions.
103*8fb009dcSAndroid Build Coastguard Worker	"neon",   // Support for NEON.
104*8fb009dcSAndroid Build Coastguard Worker	"crypto", // Support for NEON and crypto extensions.
105*8fb009dcSAndroid Build Coastguard Worker}
106*8fb009dcSAndroid Build Coastguard Worker
107*8fb009dcSAndroid Build Coastguard Workerfunc valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
108*8fb009dcSAndroid Build Coastguard Worker	valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full", "--quiet"}
109*8fb009dcSAndroid Build Coastguard Worker	if dbAttach {
110*8fb009dcSAndroid Build Coastguard Worker		valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
111*8fb009dcSAndroid Build Coastguard Worker	}
112*8fb009dcSAndroid Build Coastguard Worker	valgrindArgs = append(valgrindArgs, path)
113*8fb009dcSAndroid Build Coastguard Worker	valgrindArgs = append(valgrindArgs, args...)
114*8fb009dcSAndroid Build Coastguard Worker
115*8fb009dcSAndroid Build Coastguard Worker	return exec.Command("valgrind", valgrindArgs...)
116*8fb009dcSAndroid Build Coastguard Worker}
117*8fb009dcSAndroid Build Coastguard Worker
118*8fb009dcSAndroid Build Coastguard Workerfunc callgrindOf(path string, args ...string) *exec.Cmd {
119*8fb009dcSAndroid Build Coastguard Worker	valgrindArgs := []string{"-q", "--tool=callgrind", "--dump-instr=yes", "--collect-jumps=yes", "--callgrind-out-file=" + *buildDir + "/callgrind/callgrind.out.%p"}
120*8fb009dcSAndroid Build Coastguard Worker	valgrindArgs = append(valgrindArgs, path)
121*8fb009dcSAndroid Build Coastguard Worker	valgrindArgs = append(valgrindArgs, args...)
122*8fb009dcSAndroid Build Coastguard Worker
123*8fb009dcSAndroid Build Coastguard Worker	return exec.Command("valgrind", valgrindArgs...)
124*8fb009dcSAndroid Build Coastguard Worker}
125*8fb009dcSAndroid Build Coastguard Worker
126*8fb009dcSAndroid Build Coastguard Workerfunc gdbOf(path string, args ...string) *exec.Cmd {
127*8fb009dcSAndroid Build Coastguard Worker	xtermArgs := []string{"-e", "gdb", "--args"}
128*8fb009dcSAndroid Build Coastguard Worker	xtermArgs = append(xtermArgs, path)
129*8fb009dcSAndroid Build Coastguard Worker	xtermArgs = append(xtermArgs, args...)
130*8fb009dcSAndroid Build Coastguard Worker
131*8fb009dcSAndroid Build Coastguard Worker	return exec.Command("xterm", xtermArgs...)
132*8fb009dcSAndroid Build Coastguard Worker}
133*8fb009dcSAndroid Build Coastguard Worker
134*8fb009dcSAndroid Build Coastguard Workerfunc sdeOf(cpu, path string, args ...string) *exec.Cmd {
135*8fb009dcSAndroid Build Coastguard Worker	sdeArgs := []string{"-" + cpu}
136*8fb009dcSAndroid Build Coastguard Worker	// The kernel's vdso code for gettimeofday sometimes uses the RDTSCP
137*8fb009dcSAndroid Build Coastguard Worker	// instruction. Although SDE has a -chip_check_vsyscall flag that
138*8fb009dcSAndroid Build Coastguard Worker	// excludes such code by default, it does not seem to work. Instead,
139*8fb009dcSAndroid Build Coastguard Worker	// pass the -chip_check_exe_only flag which retains test coverage when
140*8fb009dcSAndroid Build Coastguard Worker	// statically linked and excludes the vdso.
141*8fb009dcSAndroid Build Coastguard Worker	if cpu == "p4p" || cpu == "pnr" || cpu == "mrm" || cpu == "slt" {
142*8fb009dcSAndroid Build Coastguard Worker		sdeArgs = append(sdeArgs, "-chip_check_exe_only")
143*8fb009dcSAndroid Build Coastguard Worker	}
144*8fb009dcSAndroid Build Coastguard Worker	sdeArgs = append(sdeArgs, "--", path)
145*8fb009dcSAndroid Build Coastguard Worker	sdeArgs = append(sdeArgs, args...)
146*8fb009dcSAndroid Build Coastguard Worker	return exec.Command(*sdePath, sdeArgs...)
147*8fb009dcSAndroid Build Coastguard Worker}
148*8fb009dcSAndroid Build Coastguard Worker
149*8fb009dcSAndroid Build Coastguard Workerfunc qemuOf(path string, args ...string) *exec.Cmd {
150*8fb009dcSAndroid Build Coastguard Worker	// The QEMU binary becomes the program to run, and the previous test program
151*8fb009dcSAndroid Build Coastguard Worker	// to run instead becomes an additional argument to the QEMU binary.
152*8fb009dcSAndroid Build Coastguard Worker	args = append([]string{path}, args...)
153*8fb009dcSAndroid Build Coastguard Worker	return exec.Command(*qemuBinary, args...)
154*8fb009dcSAndroid Build Coastguard Worker}
155*8fb009dcSAndroid Build Coastguard Worker
156*8fb009dcSAndroid Build Coastguard Workervar (
157*8fb009dcSAndroid Build Coastguard Worker	errMoreMallocs = errors.New("child process did not exhaust all allocation calls")
158*8fb009dcSAndroid Build Coastguard Worker	errTestSkipped = errors.New("test was skipped")
159*8fb009dcSAndroid Build Coastguard Worker)
160*8fb009dcSAndroid Build Coastguard Worker
161*8fb009dcSAndroid Build Coastguard Workerfunc runTestOnce(test test, mallocNumToFail int64) (passed bool, err error) {
162*8fb009dcSAndroid Build Coastguard Worker	prog := path.Join(*buildDir, test.Cmd[0])
163*8fb009dcSAndroid Build Coastguard Worker	args := append([]string{}, test.Cmd[1:]...)
164*8fb009dcSAndroid Build Coastguard Worker	if *simulateARMCPUs && test.cpu != "" {
165*8fb009dcSAndroid Build Coastguard Worker		args = append(args, "--cpu="+test.cpu)
166*8fb009dcSAndroid Build Coastguard Worker	}
167*8fb009dcSAndroid Build Coastguard Worker	if *useSDE {
168*8fb009dcSAndroid Build Coastguard Worker		// SDE is neither compatible with the unwind tester nor automatically
169*8fb009dcSAndroid Build Coastguard Worker		// detected.
170*8fb009dcSAndroid Build Coastguard Worker		args = append(args, "--no_unwind_tests")
171*8fb009dcSAndroid Build Coastguard Worker	}
172*8fb009dcSAndroid Build Coastguard Worker
173*8fb009dcSAndroid Build Coastguard Worker	var cmd *exec.Cmd
174*8fb009dcSAndroid Build Coastguard Worker	if *useValgrind {
175*8fb009dcSAndroid Build Coastguard Worker		cmd = valgrindOf(false, prog, args...)
176*8fb009dcSAndroid Build Coastguard Worker	} else if *useCallgrind {
177*8fb009dcSAndroid Build Coastguard Worker		cmd = callgrindOf(prog, args...)
178*8fb009dcSAndroid Build Coastguard Worker	} else if *useGDB {
179*8fb009dcSAndroid Build Coastguard Worker		cmd = gdbOf(prog, args...)
180*8fb009dcSAndroid Build Coastguard Worker	} else if *useSDE {
181*8fb009dcSAndroid Build Coastguard Worker		cmd = sdeOf(test.cpu, prog, args...)
182*8fb009dcSAndroid Build Coastguard Worker	} else if *qemuBinary != "" {
183*8fb009dcSAndroid Build Coastguard Worker		cmd = qemuOf(prog, args...)
184*8fb009dcSAndroid Build Coastguard Worker	} else {
185*8fb009dcSAndroid Build Coastguard Worker		cmd = exec.Command(prog, args...)
186*8fb009dcSAndroid Build Coastguard Worker	}
187*8fb009dcSAndroid Build Coastguard Worker	if test.Env != nil || test.numShards != 0 {
188*8fb009dcSAndroid Build Coastguard Worker		cmd.Env = make([]string, len(os.Environ()))
189*8fb009dcSAndroid Build Coastguard Worker		copy(cmd.Env, os.Environ())
190*8fb009dcSAndroid Build Coastguard Worker	}
191*8fb009dcSAndroid Build Coastguard Worker	if test.Env != nil {
192*8fb009dcSAndroid Build Coastguard Worker		cmd.Env = append(cmd.Env, test.Env...)
193*8fb009dcSAndroid Build Coastguard Worker	}
194*8fb009dcSAndroid Build Coastguard Worker	if test.numShards != 0 {
195*8fb009dcSAndroid Build Coastguard Worker		cmd.Env = append(cmd.Env, fmt.Sprintf("GTEST_SHARD_INDEX=%d", test.shard))
196*8fb009dcSAndroid Build Coastguard Worker		cmd.Env = append(cmd.Env, fmt.Sprintf("GTEST_TOTAL_SHARDS=%d", test.numShards))
197*8fb009dcSAndroid Build Coastguard Worker	}
198*8fb009dcSAndroid Build Coastguard Worker	var outBuf bytes.Buffer
199*8fb009dcSAndroid Build Coastguard Worker	cmd.Stdout = &outBuf
200*8fb009dcSAndroid Build Coastguard Worker	cmd.Stderr = &outBuf
201*8fb009dcSAndroid Build Coastguard Worker	if mallocNumToFail >= 0 {
202*8fb009dcSAndroid Build Coastguard Worker		cmd.Env = os.Environ()
203*8fb009dcSAndroid Build Coastguard Worker		cmd.Env = append(cmd.Env, "MALLOC_NUMBER_TO_FAIL="+strconv.FormatInt(mallocNumToFail, 10))
204*8fb009dcSAndroid Build Coastguard Worker		if *mallocTestDebug {
205*8fb009dcSAndroid Build Coastguard Worker			cmd.Env = append(cmd.Env, "MALLOC_ABORT_ON_FAIL=1")
206*8fb009dcSAndroid Build Coastguard Worker		}
207*8fb009dcSAndroid Build Coastguard Worker		cmd.Env = append(cmd.Env, "_MALLOC_CHECK=1")
208*8fb009dcSAndroid Build Coastguard Worker	}
209*8fb009dcSAndroid Build Coastguard Worker
210*8fb009dcSAndroid Build Coastguard Worker	if err := cmd.Start(); err != nil {
211*8fb009dcSAndroid Build Coastguard Worker		return false, err
212*8fb009dcSAndroid Build Coastguard Worker	}
213*8fb009dcSAndroid Build Coastguard Worker	if err := cmd.Wait(); err != nil {
214*8fb009dcSAndroid Build Coastguard Worker		if exitError, ok := err.(*exec.ExitError); ok {
215*8fb009dcSAndroid Build Coastguard Worker			switch exitError.Sys().(syscall.WaitStatus).ExitStatus() {
216*8fb009dcSAndroid Build Coastguard Worker			case 88:
217*8fb009dcSAndroid Build Coastguard Worker				return false, errMoreMallocs
218*8fb009dcSAndroid Build Coastguard Worker			case 89:
219*8fb009dcSAndroid Build Coastguard Worker				fmt.Print(string(outBuf.Bytes()))
220*8fb009dcSAndroid Build Coastguard Worker				return false, errTestSkipped
221*8fb009dcSAndroid Build Coastguard Worker			}
222*8fb009dcSAndroid Build Coastguard Worker		}
223*8fb009dcSAndroid Build Coastguard Worker		fmt.Print(string(outBuf.Bytes()))
224*8fb009dcSAndroid Build Coastguard Worker		return false, err
225*8fb009dcSAndroid Build Coastguard Worker	}
226*8fb009dcSAndroid Build Coastguard Worker
227*8fb009dcSAndroid Build Coastguard Worker	// Account for Windows line-endings.
228*8fb009dcSAndroid Build Coastguard Worker	stdout := bytes.Replace(outBuf.Bytes(), []byte("\r\n"), []byte("\n"), -1)
229*8fb009dcSAndroid Build Coastguard Worker
230*8fb009dcSAndroid Build Coastguard Worker	if bytes.HasSuffix(stdout, []byte("PASS\n")) &&
231*8fb009dcSAndroid Build Coastguard Worker		(len(stdout) == 5 || stdout[len(stdout)-6] == '\n') {
232*8fb009dcSAndroid Build Coastguard Worker		return true, nil
233*8fb009dcSAndroid Build Coastguard Worker	}
234*8fb009dcSAndroid Build Coastguard Worker
235*8fb009dcSAndroid Build Coastguard Worker	// Also accept a googletest-style pass line. This is left here in
236*8fb009dcSAndroid Build Coastguard Worker	// transition until the tests are all converted and this script made
237*8fb009dcSAndroid Build Coastguard Worker	// unnecessary.
238*8fb009dcSAndroid Build Coastguard Worker	if bytes.Contains(stdout, []byte("\n[  PASSED  ]")) {
239*8fb009dcSAndroid Build Coastguard Worker		return true, nil
240*8fb009dcSAndroid Build Coastguard Worker	}
241*8fb009dcSAndroid Build Coastguard Worker
242*8fb009dcSAndroid Build Coastguard Worker	fmt.Print(string(outBuf.Bytes()))
243*8fb009dcSAndroid Build Coastguard Worker	return false, nil
244*8fb009dcSAndroid Build Coastguard Worker}
245*8fb009dcSAndroid Build Coastguard Worker
246*8fb009dcSAndroid Build Coastguard Workerfunc runTest(test test) (bool, error) {
247*8fb009dcSAndroid Build Coastguard Worker	if *mallocTest < 0 {
248*8fb009dcSAndroid Build Coastguard Worker		return runTestOnce(test, -1)
249*8fb009dcSAndroid Build Coastguard Worker	}
250*8fb009dcSAndroid Build Coastguard Worker
251*8fb009dcSAndroid Build Coastguard Worker	for mallocNumToFail := int64(*mallocTest); ; mallocNumToFail++ {
252*8fb009dcSAndroid Build Coastguard Worker		if passed, err := runTestOnce(test, mallocNumToFail); err != errMoreMallocs {
253*8fb009dcSAndroid Build Coastguard Worker			if err != nil {
254*8fb009dcSAndroid Build Coastguard Worker				err = fmt.Errorf("at malloc %d: %s", mallocNumToFail, err)
255*8fb009dcSAndroid Build Coastguard Worker			}
256*8fb009dcSAndroid Build Coastguard Worker			return passed, err
257*8fb009dcSAndroid Build Coastguard Worker		}
258*8fb009dcSAndroid Build Coastguard Worker	}
259*8fb009dcSAndroid Build Coastguard Worker}
260*8fb009dcSAndroid Build Coastguard Worker
261*8fb009dcSAndroid Build Coastguard Worker// setWorkingDirectory walks up directories as needed until the current working
262*8fb009dcSAndroid Build Coastguard Worker// directory is the top of a BoringSSL checkout.
263*8fb009dcSAndroid Build Coastguard Workerfunc setWorkingDirectory() {
264*8fb009dcSAndroid Build Coastguard Worker	for i := 0; i < 64; i++ {
265*8fb009dcSAndroid Build Coastguard Worker		if _, err := os.Stat("BUILDING.md"); err == nil {
266*8fb009dcSAndroid Build Coastguard Worker			return
267*8fb009dcSAndroid Build Coastguard Worker		}
268*8fb009dcSAndroid Build Coastguard Worker		os.Chdir("..")
269*8fb009dcSAndroid Build Coastguard Worker	}
270*8fb009dcSAndroid Build Coastguard Worker
271*8fb009dcSAndroid Build Coastguard Worker	panic("Couldn't find BUILDING.md in a parent directory!")
272*8fb009dcSAndroid Build Coastguard Worker}
273*8fb009dcSAndroid Build Coastguard Worker
274*8fb009dcSAndroid Build Coastguard Workerfunc worker(tests <-chan test, results chan<- result, done *sync.WaitGroup) {
275*8fb009dcSAndroid Build Coastguard Worker	defer done.Done()
276*8fb009dcSAndroid Build Coastguard Worker	for test := range tests {
277*8fb009dcSAndroid Build Coastguard Worker		passed, err := runTest(test)
278*8fb009dcSAndroid Build Coastguard Worker		results <- result{test, passed, err}
279*8fb009dcSAndroid Build Coastguard Worker	}
280*8fb009dcSAndroid Build Coastguard Worker}
281*8fb009dcSAndroid Build Coastguard Worker
282*8fb009dcSAndroid Build Coastguard Workerfunc (t test) shortName() string {
283*8fb009dcSAndroid Build Coastguard Worker	return strings.Join(t.Cmd, " ") + t.shardMsg() + t.cpuMsg() + t.envMsg()
284*8fb009dcSAndroid Build Coastguard Worker}
285*8fb009dcSAndroid Build Coastguard Worker
286*8fb009dcSAndroid Build Coastguard Workerfunc SpaceIf(returnSpace bool) string {
287*8fb009dcSAndroid Build Coastguard Worker	if !returnSpace {
288*8fb009dcSAndroid Build Coastguard Worker		return ""
289*8fb009dcSAndroid Build Coastguard Worker	}
290*8fb009dcSAndroid Build Coastguard Worker	return " "
291*8fb009dcSAndroid Build Coastguard Worker}
292*8fb009dcSAndroid Build Coastguard Worker
293*8fb009dcSAndroid Build Coastguard Workerfunc (t test) longName() string {
294*8fb009dcSAndroid Build Coastguard Worker	return strings.Join(t.Env, " ") + SpaceIf(len(t.Env) != 0) + strings.Join(t.Cmd, " ") + t.shardMsg() + t.cpuMsg()
295*8fb009dcSAndroid Build Coastguard Worker}
296*8fb009dcSAndroid Build Coastguard Worker
297*8fb009dcSAndroid Build Coastguard Workerfunc (t test) shardMsg() string {
298*8fb009dcSAndroid Build Coastguard Worker	if t.numShards == 0 {
299*8fb009dcSAndroid Build Coastguard Worker		return ""
300*8fb009dcSAndroid Build Coastguard Worker	}
301*8fb009dcSAndroid Build Coastguard Worker
302*8fb009dcSAndroid Build Coastguard Worker	return fmt.Sprintf(" [shard %d/%d]", t.shard+1, t.numShards)
303*8fb009dcSAndroid Build Coastguard Worker}
304*8fb009dcSAndroid Build Coastguard Worker
305*8fb009dcSAndroid Build Coastguard Workerfunc (t test) cpuMsg() string {
306*8fb009dcSAndroid Build Coastguard Worker	if len(t.cpu) == 0 {
307*8fb009dcSAndroid Build Coastguard Worker		return ""
308*8fb009dcSAndroid Build Coastguard Worker	}
309*8fb009dcSAndroid Build Coastguard Worker
310*8fb009dcSAndroid Build Coastguard Worker	return fmt.Sprintf(" (for CPU %q)", t.cpu)
311*8fb009dcSAndroid Build Coastguard Worker}
312*8fb009dcSAndroid Build Coastguard Worker
313*8fb009dcSAndroid Build Coastguard Workerfunc (t test) envMsg() string {
314*8fb009dcSAndroid Build Coastguard Worker	if len(t.Env) == 0 {
315*8fb009dcSAndroid Build Coastguard Worker		return ""
316*8fb009dcSAndroid Build Coastguard Worker	}
317*8fb009dcSAndroid Build Coastguard Worker
318*8fb009dcSAndroid Build Coastguard Worker	return " (custom environment)"
319*8fb009dcSAndroid Build Coastguard Worker}
320*8fb009dcSAndroid Build Coastguard Worker
321*8fb009dcSAndroid Build Coastguard Workerfunc (t test) getGTestShards() ([]test, error) {
322*8fb009dcSAndroid Build Coastguard Worker	if *numWorkers == 1 || !t.Shard {
323*8fb009dcSAndroid Build Coastguard Worker		return []test{t}, nil
324*8fb009dcSAndroid Build Coastguard Worker	}
325*8fb009dcSAndroid Build Coastguard Worker
326*8fb009dcSAndroid Build Coastguard Worker	shards := make([]test, *numWorkers)
327*8fb009dcSAndroid Build Coastguard Worker	for i := range shards {
328*8fb009dcSAndroid Build Coastguard Worker		shards[i] = t
329*8fb009dcSAndroid Build Coastguard Worker		shards[i].shard = i
330*8fb009dcSAndroid Build Coastguard Worker		shards[i].numShards = *numWorkers
331*8fb009dcSAndroid Build Coastguard Worker	}
332*8fb009dcSAndroid Build Coastguard Worker
333*8fb009dcSAndroid Build Coastguard Worker	return shards, nil
334*8fb009dcSAndroid Build Coastguard Worker}
335*8fb009dcSAndroid Build Coastguard Worker
336*8fb009dcSAndroid Build Coastguard Workerfunc main() {
337*8fb009dcSAndroid Build Coastguard Worker	flag.Parse()
338*8fb009dcSAndroid Build Coastguard Worker	setWorkingDirectory()
339*8fb009dcSAndroid Build Coastguard Worker
340*8fb009dcSAndroid Build Coastguard Worker	testCases, err := testconfig.ParseTestConfig("util/all_tests.json")
341*8fb009dcSAndroid Build Coastguard Worker	if err != nil {
342*8fb009dcSAndroid Build Coastguard Worker		fmt.Printf("Failed to parse input: %s\n", err)
343*8fb009dcSAndroid Build Coastguard Worker		os.Exit(1)
344*8fb009dcSAndroid Build Coastguard Worker	}
345*8fb009dcSAndroid Build Coastguard Worker
346*8fb009dcSAndroid Build Coastguard Worker	var wg sync.WaitGroup
347*8fb009dcSAndroid Build Coastguard Worker	tests := make(chan test, *numWorkers)
348*8fb009dcSAndroid Build Coastguard Worker	results := make(chan result, *numWorkers)
349*8fb009dcSAndroid Build Coastguard Worker
350*8fb009dcSAndroid Build Coastguard Worker	for i := 0; i < *numWorkers; i++ {
351*8fb009dcSAndroid Build Coastguard Worker		wg.Add(1)
352*8fb009dcSAndroid Build Coastguard Worker		go worker(tests, results, &wg)
353*8fb009dcSAndroid Build Coastguard Worker	}
354*8fb009dcSAndroid Build Coastguard Worker
355*8fb009dcSAndroid Build Coastguard Worker	go func() {
356*8fb009dcSAndroid Build Coastguard Worker		for _, baseTest := range testCases {
357*8fb009dcSAndroid Build Coastguard Worker			test := test{Test: baseTest}
358*8fb009dcSAndroid Build Coastguard Worker			if *useSDE {
359*8fb009dcSAndroid Build Coastguard Worker				if test.SkipSDE {
360*8fb009dcSAndroid Build Coastguard Worker					continue
361*8fb009dcSAndroid Build Coastguard Worker				}
362*8fb009dcSAndroid Build Coastguard Worker				// SDE generates plenty of tasks and gets slower
363*8fb009dcSAndroid Build Coastguard Worker				// with additional sharding.
364*8fb009dcSAndroid Build Coastguard Worker				for _, cpu := range sdeCPUs {
365*8fb009dcSAndroid Build Coastguard Worker					testForCPU := test
366*8fb009dcSAndroid Build Coastguard Worker					testForCPU.cpu = cpu
367*8fb009dcSAndroid Build Coastguard Worker					tests <- testForCPU
368*8fb009dcSAndroid Build Coastguard Worker				}
369*8fb009dcSAndroid Build Coastguard Worker			} else if *simulateARMCPUs {
370*8fb009dcSAndroid Build Coastguard Worker				// This mode is run instead of the default path,
371*8fb009dcSAndroid Build Coastguard Worker				// so also include the native flow.
372*8fb009dcSAndroid Build Coastguard Worker				tests <- test
373*8fb009dcSAndroid Build Coastguard Worker				for _, cpu := range armCPUs {
374*8fb009dcSAndroid Build Coastguard Worker					testForCPU := test
375*8fb009dcSAndroid Build Coastguard Worker					testForCPU.cpu = cpu
376*8fb009dcSAndroid Build Coastguard Worker					tests <- testForCPU
377*8fb009dcSAndroid Build Coastguard Worker				}
378*8fb009dcSAndroid Build Coastguard Worker			} else {
379*8fb009dcSAndroid Build Coastguard Worker				shards, err := test.getGTestShards()
380*8fb009dcSAndroid Build Coastguard Worker				if err != nil {
381*8fb009dcSAndroid Build Coastguard Worker					fmt.Printf("Error listing tests: %s\n", err)
382*8fb009dcSAndroid Build Coastguard Worker					os.Exit(1)
383*8fb009dcSAndroid Build Coastguard Worker				}
384*8fb009dcSAndroid Build Coastguard Worker				for _, shard := range shards {
385*8fb009dcSAndroid Build Coastguard Worker					tests <- shard
386*8fb009dcSAndroid Build Coastguard Worker				}
387*8fb009dcSAndroid Build Coastguard Worker			}
388*8fb009dcSAndroid Build Coastguard Worker		}
389*8fb009dcSAndroid Build Coastguard Worker		close(tests)
390*8fb009dcSAndroid Build Coastguard Worker
391*8fb009dcSAndroid Build Coastguard Worker		wg.Wait()
392*8fb009dcSAndroid Build Coastguard Worker		close(results)
393*8fb009dcSAndroid Build Coastguard Worker	}()
394*8fb009dcSAndroid Build Coastguard Worker
395*8fb009dcSAndroid Build Coastguard Worker	testOutput := testresult.NewResults()
396*8fb009dcSAndroid Build Coastguard Worker	var failed, skipped []test
397*8fb009dcSAndroid Build Coastguard Worker	for testResult := range results {
398*8fb009dcSAndroid Build Coastguard Worker		test := testResult.Test
399*8fb009dcSAndroid Build Coastguard Worker		args := test.Cmd
400*8fb009dcSAndroid Build Coastguard Worker
401*8fb009dcSAndroid Build Coastguard Worker		if testResult.Error == errTestSkipped {
402*8fb009dcSAndroid Build Coastguard Worker			fmt.Printf("%s\n", test.longName())
403*8fb009dcSAndroid Build Coastguard Worker			fmt.Printf("%s was skipped\n", args[0])
404*8fb009dcSAndroid Build Coastguard Worker			skipped = append(skipped, test)
405*8fb009dcSAndroid Build Coastguard Worker			testOutput.AddSkip(test.longName())
406*8fb009dcSAndroid Build Coastguard Worker		} else if testResult.Error != nil {
407*8fb009dcSAndroid Build Coastguard Worker			fmt.Printf("%s\n", test.longName())
408*8fb009dcSAndroid Build Coastguard Worker			fmt.Printf("%s failed to complete: %s\n", args[0], testResult.Error)
409*8fb009dcSAndroid Build Coastguard Worker			failed = append(failed, test)
410*8fb009dcSAndroid Build Coastguard Worker			testOutput.AddResult(test.longName(), "CRASH", testResult.Error)
411*8fb009dcSAndroid Build Coastguard Worker		} else if !testResult.Passed {
412*8fb009dcSAndroid Build Coastguard Worker			fmt.Printf("%s\n", test.longName())
413*8fb009dcSAndroid Build Coastguard Worker			fmt.Printf("%s failed to print PASS on the last line.\n", args[0])
414*8fb009dcSAndroid Build Coastguard Worker			failed = append(failed, test)
415*8fb009dcSAndroid Build Coastguard Worker			testOutput.AddResult(test.longName(), "FAIL", nil)
416*8fb009dcSAndroid Build Coastguard Worker		} else {
417*8fb009dcSAndroid Build Coastguard Worker			fmt.Printf("%s\n", test.shortName())
418*8fb009dcSAndroid Build Coastguard Worker			testOutput.AddResult(test.longName(), "PASS", nil)
419*8fb009dcSAndroid Build Coastguard Worker		}
420*8fb009dcSAndroid Build Coastguard Worker	}
421*8fb009dcSAndroid Build Coastguard Worker
422*8fb009dcSAndroid Build Coastguard Worker	if *jsonOutput != "" {
423*8fb009dcSAndroid Build Coastguard Worker		if err := testOutput.WriteToFile(*jsonOutput); err != nil {
424*8fb009dcSAndroid Build Coastguard Worker			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
425*8fb009dcSAndroid Build Coastguard Worker		}
426*8fb009dcSAndroid Build Coastguard Worker	}
427*8fb009dcSAndroid Build Coastguard Worker
428*8fb009dcSAndroid Build Coastguard Worker	if len(skipped) > 0 {
429*8fb009dcSAndroid Build Coastguard Worker		fmt.Printf("\n%d of %d tests were skipped:\n", len(skipped), len(testCases))
430*8fb009dcSAndroid Build Coastguard Worker		for _, test := range skipped {
431*8fb009dcSAndroid Build Coastguard Worker			fmt.Printf("\t%s\n", test.shortName())
432*8fb009dcSAndroid Build Coastguard Worker		}
433*8fb009dcSAndroid Build Coastguard Worker	}
434*8fb009dcSAndroid Build Coastguard Worker
435*8fb009dcSAndroid Build Coastguard Worker	if len(failed) > 0 {
436*8fb009dcSAndroid Build Coastguard Worker		fmt.Printf("\n%d of %d tests failed:\n", len(failed), len(testCases))
437*8fb009dcSAndroid Build Coastguard Worker		for _, test := range failed {
438*8fb009dcSAndroid Build Coastguard Worker			fmt.Printf("\t%s\n", test.shortName())
439*8fb009dcSAndroid Build Coastguard Worker		}
440*8fb009dcSAndroid Build Coastguard Worker		os.Exit(1)
441*8fb009dcSAndroid Build Coastguard Worker	}
442*8fb009dcSAndroid Build Coastguard Worker
443*8fb009dcSAndroid Build Coastguard Worker	fmt.Printf("All unit tests passed!\n")
444*8fb009dcSAndroid Build Coastguard Worker}
445