diff options
Diffstat (limited to 'compiler_wrapper/crash_builds_test.go')
-rw-r--r-- | compiler_wrapper/crash_builds_test.go | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/compiler_wrapper/crash_builds_test.go b/compiler_wrapper/crash_builds_test.go new file mode 100644 index 00000000..3d33d933 --- /dev/null +++ b/compiler_wrapper/crash_builds_test.go @@ -0,0 +1,260 @@ +// Copyright 2022 The ChromiumOS Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package main + +import ( + "bytes" + "io" + "strings" + "testing" +) + +func TestBuildWithAutoCrashDoesNothingIfCrashIsNotRequested(t *testing.T) { + withTestContext(t, func(ctx *testContext) { + neverAutoCrash := buildWithAutocrashPredicates{ + allowInConfigure: true, + shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool { + return false + }, + } + + exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc), neverAutoCrash) + if err != nil { + t.Fatalf("unexpectedly failed with %v", err) + } + ctx.must(exitCode) + if ctx.cmdCount != 1 { + t.Errorf("expected 1 call. Got: %d", ctx.cmdCount) + } + }) +} + +func TestBuildWithAutoCrashSkipsAutocrashLogicIfInConfigureAndConfigureChecksDisabled(t *testing.T) { + withTestContext(t, func(ctx *testContext) { + alwaysAutocrash := buildWithAutocrashPredicates{ + allowInConfigure: false, + shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool { + return true + }, + } + + ctx.env = append(ctx.env, "EBUILD_PHASE=configure") + exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc), alwaysAutocrash) + if err != nil { + t.Fatalf("unexpectedly failed with %v", err) + } + ctx.must(exitCode) + if ctx.cmdCount != 1 { + t.Errorf("expected 1 call. Got: %d", ctx.cmdCount) + } + }) +} + +func TestBuildWithAutoCrashRerunsIfPredicateRequestsCrash(t *testing.T) { + withTestContext(t, func(ctx *testContext) { + autocrashPostCmd := buildWithAutocrashPredicates{ + allowInConfigure: true, + shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool { + return true + }, + } + + ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { + hasDash := false + for _, arg := range cmd.Args { + if arg == "-" { + hasDash = true + break + } + } + + switch ctx.cmdCount { + case 1: + if hasDash { + t.Error("Got `-` on command 1; didn't want that.") + } + return nil + case 2: + if !hasDash { + t.Error("Didn't get `-` on command 2; wanted that.") + } else { + input := stdin.(*bytes.Buffer) + if s := input.String(); !strings.Contains(s, autocrashProgramLine) { + t.Errorf("Input was %q; expected %q to be in it", s, autocrashProgramLine) + } + } + return nil + default: + t.Fatalf("Unexpected command count: %d", ctx.cmdCount) + panic("Unreachable") + } + } + + exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc), autocrashPostCmd) + if err != nil { + t.Fatalf("unexpectedly failed with %v", err) + } + ctx.must(exitCode) + + if ctx.cmdCount != 2 { + t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount) + } + }) +} + +func TestBuildWithAutoCrashAddsDashAndWritesToStdinIfInputFileIsNotStdin(t *testing.T) { + withTestContext(t, func(ctx *testContext) { + autocrashPostCmd := buildWithAutocrashPredicates{ + allowInConfigure: true, + shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool { + return true + }, + } + + ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { + numDashes := 0 + for _, arg := range cmd.Args { + if arg == "-" { + numDashes++ + } + } + + switch ctx.cmdCount { + case 1: + if numDashes != 0 { + t.Errorf("Got %d dashes on command 1; want 0", numDashes) + } + return nil + case 2: + if numDashes != 1 { + t.Errorf("Got %d dashes on command 2; want 1", numDashes) + } + + input := stdin.(*bytes.Buffer).String() + stdinHasAutocrashLine := strings.Contains(input, autocrashProgramLine) + if !stdinHasAutocrashLine { + t.Error("Got no autocrash line on the second command; wanted that") + } + return nil + default: + t.Fatalf("Unexpected command count: %d", ctx.cmdCount) + panic("Unreachable") + } + } + + exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc), autocrashPostCmd) + if err != nil { + t.Fatalf("unexpectedly failed with %v", err) + } + ctx.must(exitCode) + + if ctx.cmdCount != 2 { + t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount) + } + }) +} + +func TestBuildWithAutoCrashAppendsToStdinIfStdinIsTheOnlyInputFile(t *testing.T) { + withTestContext(t, func(ctx *testContext) { + autocrashPostCmd := buildWithAutocrashPredicates{ + allowInConfigure: true, + shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool { + return true + }, + } + + ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { + numDashes := 0 + for _, arg := range cmd.Args { + if arg == "-" { + numDashes++ + } + } + + if numDashes != 1 { + t.Errorf("Got %d dashes on command %d (args: %#v); want 1", numDashes, ctx.cmdCount, cmd.Args) + } + + input := stdin.(*bytes.Buffer).String() + stdinHasAutocrashLine := strings.Contains(input, autocrashProgramLine) + + switch ctx.cmdCount { + case 1: + if stdinHasAutocrashLine { + t.Error("Got autocrash line on the first command; did not want that") + } + return nil + case 2: + if !stdinHasAutocrashLine { + t.Error("Got no autocrash line on the second command; wanted that") + } + return nil + default: + t.Fatalf("Unexpected command count: %d", ctx.cmdCount) + panic("Unreachable") + } + } + + exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, "-x", "c", "-"), autocrashPostCmd) + if err != nil { + t.Fatalf("unexpectedly failed with %v", err) + } + ctx.must(exitCode) + + if ctx.cmdCount != 2 { + t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount) + } + }) +} + +func TestCrashBuildFiltersObjectFileOptionOnCrashes(t *testing.T) { + withTestContext(t, func(ctx *testContext) { + autocrashPostCmd := buildWithAutocrashPredicates{ + allowInConfigure: true, + shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool { + return true + }, + } + + const outputFileName = "/path/to/foo.o" + + ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { + cmdOutputArg := (*string)(nil) + for i, e := range cmd.Args { + if e == "-o" { + // Assume something follows. If not, we'll crash and the + // test will fail. + cmdOutputArg = &cmd.Args[i+1] + } + } + + switch ctx.cmdCount { + case 1: + if cmdOutputArg == nil || *cmdOutputArg != outputFileName { + t.Errorf("Got command args %q; want `-o %q` in them", cmd.Args, outputFileName) + } + return nil + case 2: + if cmdOutputArg != nil { + t.Errorf("Got command args %q; want no mention of `-o %q` in them", cmd.Args, outputFileName) + } + return nil + default: + t.Fatalf("Unexpected command count: %d", ctx.cmdCount) + panic("Unreachable") + } + } + + exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, "-o", outputFileName, mainCc), autocrashPostCmd) + if err != nil { + t.Fatalf("unexpectedly failed with %v", err) + } + ctx.must(exitCode) + + if ctx.cmdCount != 2 { + t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount) + } + }) +} |