aboutsummaryrefslogtreecommitdiff
path: root/compiler_wrapper/crash_builds_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_wrapper/crash_builds_test.go')
-rw-r--r--compiler_wrapper/crash_builds_test.go260
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)
+ }
+ })
+}