xref: /aosp_15_r20/external/toolchain-utils/compiler_wrapper/bisect_flag_test.go (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1*760c253cSXin Li// Copyright 2019 The ChromiumOS Authors
2*760c253cSXin Li// Use of this source code is governed by a BSD-style license that can be
3*760c253cSXin Li// found in the LICENSE file.
4*760c253cSXin Li
5*760c253cSXin Lipackage main
6*760c253cSXin Li
7*760c253cSXin Liimport (
8*760c253cSXin Li	"errors"
9*760c253cSXin Li	"fmt"
10*760c253cSXin Li	"io"
11*760c253cSXin Li	"path/filepath"
12*760c253cSXin Li	"strings"
13*760c253cSXin Li	"testing"
14*760c253cSXin Li)
15*760c253cSXin Li
16*760c253cSXin Lifunc TestCallBisectDriver(t *testing.T) {
17*760c253cSXin Li	withBisectTestContext(t, func(ctx *testContext) {
18*760c253cSXin Li		ctx.env = []string{
19*760c253cSXin Li			"BISECT_STAGE=someBisectStage",
20*760c253cSXin Li			"BISECT_DIR=someBisectDir",
21*760c253cSXin Li		}
22*760c253cSXin Li		cmd := mustCallBisectDriver(ctx, callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc)))
23*760c253cSXin Li		if err := verifyPath(cmd, "bisect_driver"); err != nil {
24*760c253cSXin Li			t.Error(err)
25*760c253cSXin Li		}
26*760c253cSXin Li		if err := verifyArgOrder(cmd,
27*760c253cSXin Li			"someBisectStage", "someBisectDir", filepath.Join(ctx.tempDir, gccX86_64+".real"), "--sysroot=.*", mainCc); err != nil {
28*760c253cSXin Li			t.Error(err)
29*760c253cSXin Li		}
30*760c253cSXin Li	})
31*760c253cSXin Li}
32*760c253cSXin Li
33*760c253cSXin Lifunc TestCallBisectDriverWithParamsFile(t *testing.T) {
34*760c253cSXin Li	withBisectTestContext(t, func(ctx *testContext) {
35*760c253cSXin Li		ctx.env = []string{
36*760c253cSXin Li			"BISECT_STAGE=someBisectStage",
37*760c253cSXin Li			"BISECT_DIR=someBisectDir",
38*760c253cSXin Li		}
39*760c253cSXin Li		paramsFile1 := filepath.Join(ctx.tempDir, "params1")
40*760c253cSXin Li		ctx.writeFile(paramsFile1, "a\n#comment\n@params2")
41*760c253cSXin Li		paramsFile2 := filepath.Join(ctx.tempDir, "params2")
42*760c253cSXin Li		ctx.writeFile(paramsFile2, "b\n"+mainCc)
43*760c253cSXin Li
44*760c253cSXin Li		cmd := mustCallBisectDriver(ctx, callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, "@"+paramsFile1)))
45*760c253cSXin Li		if err := verifyArgOrder(cmd,
46*760c253cSXin Li			"a", "b", mainCc); err != nil {
47*760c253cSXin Li			t.Error(err)
48*760c253cSXin Li		}
49*760c253cSXin Li	})
50*760c253cSXin Li}
51*760c253cSXin Li
52*760c253cSXin Lifunc TestCallBisectDriverWithCCache(t *testing.T) {
53*760c253cSXin Li	withBisectTestContext(t, func(ctx *testContext) {
54*760c253cSXin Li		ctx.cfg.useCCache = true
55*760c253cSXin Li		cmd := ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc)))
56*760c253cSXin Li		if err := verifyPath(cmd, "/usr/bin/env"); err != nil {
57*760c253cSXin Li			t.Error(err)
58*760c253cSXin Li		}
59*760c253cSXin Li		if err := verifyArgOrder(cmd, "python3", "/usr/bin/ccache"); err != nil {
60*760c253cSXin Li			t.Error(err)
61*760c253cSXin Li		}
62*760c253cSXin Li		if err := verifyEnvUpdate(cmd, "CCACHE_DIR=.*"); err != nil {
63*760c253cSXin Li			t.Error(err)
64*760c253cSXin Li		}
65*760c253cSXin Li	})
66*760c253cSXin Li}
67*760c253cSXin Li
68*760c253cSXin Lifunc TestDefaultBisectDirCros(t *testing.T) {
69*760c253cSXin Li	withBisectTestContext(t, func(ctx *testContext) {
70*760c253cSXin Li		ctx.env = []string{
71*760c253cSXin Li			"BISECT_STAGE=someBisectStage",
72*760c253cSXin Li		}
73*760c253cSXin Li		cmd := mustCallBisectDriver(ctx, callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc)))
74*760c253cSXin Li		if err := verifyArgOrder(cmd,
75*760c253cSXin Li			"someBisectStage", "/tmp/sysroot_bisect"); err != nil {
76*760c253cSXin Li			t.Error(err)
77*760c253cSXin Li		}
78*760c253cSXin Li	})
79*760c253cSXin Li}
80*760c253cSXin Li
81*760c253cSXin Lifunc TestDefaultBisectDirAndroid(t *testing.T) {
82*760c253cSXin Li	withBisectTestContext(t, func(ctx *testContext) {
83*760c253cSXin Li		ctx.env = []string{
84*760c253cSXin Li			"BISECT_STAGE=someBisectStage",
85*760c253cSXin Li			"HOME=/somehome",
86*760c253cSXin Li		}
87*760c253cSXin Li		ctx.cfg.isAndroidWrapper = true
88*760c253cSXin Li		cmd := mustCallBisectDriver(ctx, callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, mainCc)))
89*760c253cSXin Li		if err := verifyArgOrder(cmd,
90*760c253cSXin Li			"someBisectStage", filepath.Join("/somehome", "ANDROID_BISECT")); err != nil {
91*760c253cSXin Li			t.Error(err)
92*760c253cSXin Li		}
93*760c253cSXin Li	})
94*760c253cSXin Li}
95*760c253cSXin Li
96*760c253cSXin Lifunc TestForwardStdOutAndStdErrAndExitCodeFromBisect(t *testing.T) {
97*760c253cSXin Li	withBisectTestContext(t, func(ctx *testContext) {
98*760c253cSXin Li		ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
99*760c253cSXin Li			fmt.Fprint(stdout, "somemessage")
100*760c253cSXin Li			fmt.Fprint(stderr, "someerror")
101*760c253cSXin Li			return newExitCodeError(23)
102*760c253cSXin Li		}
103*760c253cSXin Li		exitCode := callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc))
104*760c253cSXin Li		if exitCode != 23 {
105*760c253cSXin Li			t.Errorf("unexpected exit code. Got: %d", exitCode)
106*760c253cSXin Li		}
107*760c253cSXin Li		if ctx.stdoutString() != "somemessage" {
108*760c253cSXin Li			t.Errorf("stdout was not forwarded. Got: %s", ctx.stdoutString())
109*760c253cSXin Li		}
110*760c253cSXin Li		if ctx.stderrString() != "someerror" {
111*760c253cSXin Li			t.Errorf("stderr was not forwarded. Got: %s", ctx.stderrString())
112*760c253cSXin Li		}
113*760c253cSXin Li	})
114*760c253cSXin Li}
115*760c253cSXin Li
116*760c253cSXin Lifunc TestForwardGeneralErrorFromBisect(t *testing.T) {
117*760c253cSXin Li	withBisectTestContext(t, func(ctx *testContext) {
118*760c253cSXin Li		ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
119*760c253cSXin Li			return errors.New("someerror")
120*760c253cSXin Li		}
121*760c253cSXin Li		stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg,
122*760c253cSXin Li			ctx.newCommand(gccX86_64, mainCc)))
123*760c253cSXin Li		if err := verifyInternalError(stderr); err != nil {
124*760c253cSXin Li			t.Fatal(err)
125*760c253cSXin Li		}
126*760c253cSXin Li		if !strings.Contains(stderr, "someerror") {
127*760c253cSXin Li			t.Errorf("unexpected error. Got: %s", stderr)
128*760c253cSXin Li		}
129*760c253cSXin Li	})
130*760c253cSXin Li}
131*760c253cSXin Li
132*760c253cSXin Lifunc withBisectTestContext(t *testing.T, work func(ctx *testContext)) {
133*760c253cSXin Li	withTestContext(t, func(ctx *testContext) {
134*760c253cSXin Li		ctx.env = []string{"BISECT_STAGE=xyz"}
135*760c253cSXin Li		// We execute the python script but replace the call to the bisect_driver with
136*760c253cSXin Li		// a mock that logs the data.
137*760c253cSXin Li		ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
138*760c253cSXin Li			if err := verifyPath(cmd, "/usr/bin/env"); err != nil {
139*760c253cSXin Li				return err
140*760c253cSXin Li			}
141*760c253cSXin Li			if cmd.Args[0] != "python3" {
142*760c253cSXin Li				return fmt.Errorf("expected a call to python. Got: %s", cmd.Args[0])
143*760c253cSXin Li			}
144*760c253cSXin Li			if cmd.Args[1] != "-c" {
145*760c253cSXin Li				return fmt.Errorf("expected an inline python script. Got: %s", cmd.Args)
146*760c253cSXin Li			}
147*760c253cSXin Li			script := cmd.Args[2]
148*760c253cSXin Li			mock := `
149*760c253cSXin Liclass BisectDriver:
150*760c253cSXin Li	def __init__(self):
151*760c253cSXin Li		self.VALID_MODES = ['POPULATE_GOOD', 'POPULATE_BAD', 'TRIAGE']
152*760c253cSXin Li	def bisect_driver(self, bisect_stage, bisect_dir, execargs):
153*760c253cSXin Li		print('command bisect_driver')
154*760c253cSXin Li		print('arg %s' % bisect_stage)
155*760c253cSXin Li		print('arg %s' % bisect_dir)
156*760c253cSXin Li		for arg in execargs:
157*760c253cSXin Li			print('arg %s' % arg)
158*760c253cSXin Li
159*760c253cSXin Libisect_driver = BisectDriver()
160*760c253cSXin Li`
161*760c253cSXin Li			script = mock + script
162*760c253cSXin Li			script = strings.Replace(script, "import bisect_driver", "", -1)
163*760c253cSXin Li			cmdCopy := *cmd
164*760c253cSXin Li			cmdCopy.Args = append(append(cmd.Args[:2], script), cmd.Args[3:]...)
165*760c253cSXin Li			// Evaluate the python script, but replace the call to the bisect_driver
166*760c253cSXin Li			// with a log statement so that we can assert it.
167*760c253cSXin Li			return runCmd(ctx, &cmdCopy, nil, stdout, stderr)
168*760c253cSXin Li		}
169*760c253cSXin Li		work(ctx)
170*760c253cSXin Li	})
171*760c253cSXin Li}
172*760c253cSXin Li
173*760c253cSXin Lifunc mustCallBisectDriver(ctx *testContext, exitCode int) *command {
174*760c253cSXin Li	ctx.must(exitCode)
175*760c253cSXin Li	cmd := &command{}
176*760c253cSXin Li	for _, line := range strings.Split(ctx.stdoutString(), "\n") {
177*760c253cSXin Li		if prefix := "command "; strings.HasPrefix(line, prefix) {
178*760c253cSXin Li			cmd.Path = line[len(prefix):]
179*760c253cSXin Li		} else if prefix := "arg "; strings.HasPrefix(line, prefix) {
180*760c253cSXin Li			cmd.Args = append(cmd.Args, line[len(prefix):])
181*760c253cSXin Li		}
182*760c253cSXin Li	}
183*760c253cSXin Li	return cmd
184*760c253cSXin Li}
185