aboutsummaryrefslogtreecommitdiff
path: root/compiler_wrapper/compile_with_fallback_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_wrapper/compile_with_fallback_test.go')
-rw-r--r--compiler_wrapper/compile_with_fallback_test.go292
1 files changed, 292 insertions, 0 deletions
diff --git a/compiler_wrapper/compile_with_fallback_test.go b/compiler_wrapper/compile_with_fallback_test.go
new file mode 100644
index 00000000..32d1915b
--- /dev/null
+++ b/compiler_wrapper/compile_with_fallback_test.go
@@ -0,0 +1,292 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package main
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func TestOmitFallbackCompileForSuccessfulCall(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, mainCc)))
+ if ctx.cmdCount != 1 {
+ t.Errorf("expected 1 call. Got: %d", ctx.cmdCount)
+ }
+ })
+}
+
+func TestOmitFallbackCompileForGeneralError(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
+ return errors.New("someerror")
+ }
+ stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, mainCc)))
+ if err := verifyInternalError(stderr); err != nil {
+ t.Fatal(err)
+ }
+ if !strings.Contains(stderr, "someerror") {
+ t.Errorf("unexpected error. Got: %s", stderr)
+ }
+ if ctx.cmdCount != 1 {
+ t.Errorf("expected 1 call. Got: %d", ctx.cmdCount)
+ }
+ })
+}
+
+func TestCompileWithFallbackForNonZeroExitCode(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
+ switch ctx.cmdCount {
+ case 1:
+ return newExitCodeError(1)
+ case 2:
+ if err := verifyPath(cmd, "fallback_compiler/clang"); err != nil {
+ return err
+ }
+ if err := verifyEnvUpdate(cmd, "ANDROID_LLVM_PREBUILT_COMPILER_PATH="); err != nil {
+ return err
+ }
+ return nil
+ default:
+ t.Fatalf("unexpected command: %#v", cmd)
+ return nil
+ }
+ }
+ ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, mainCc)))
+ if ctx.cmdCount != 2 {
+ t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount)
+ }
+ })
+}
+
+func TestCompileWithFallbackForwardStdoutAndStderr(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
+ switch ctx.cmdCount {
+ case 1:
+ fmt.Fprint(stdout, "originalmessage")
+ fmt.Fprint(stderr, "originalerror")
+ return newExitCodeError(1)
+ case 2:
+ fmt.Fprint(stdout, "fallbackmessage")
+ fmt.Fprint(stderr, "fallbackerror")
+ return nil
+ default:
+ t.Fatalf("unexpected command: %#v", cmd)
+ return nil
+ }
+ }
+ ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, mainCc)))
+ if err := verifyNonInternalError(ctx.stderrString(), "originalerrorfallbackerror"); err != nil {
+ t.Error(err)
+ }
+ if !strings.Contains(ctx.stdoutString(), "originalmessagefallbackmessage") {
+ t.Errorf("unexpected stdout. Got: %s", ctx.stdoutString())
+ }
+ })
+}
+
+func TestForwardGeneralErrorWhenFallbackCompileFails(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
+ switch ctx.cmdCount {
+ case 1:
+ return newExitCodeError(1)
+ case 2:
+ return errors.New("someerror")
+ default:
+ t.Fatalf("unexpected command: %#v", cmd)
+ return nil
+ }
+ }
+ stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, mainCc)))
+ if err := verifyInternalError(stderr); err != nil {
+ t.Error(err)
+ }
+ if !strings.Contains(stderr, "someerror") {
+ t.Errorf("unexpected stderr. Got: %s", stderr)
+ }
+ })
+}
+
+func TestForwardExitCodeWhenFallbackCompileFails(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
+ switch ctx.cmdCount {
+ case 1:
+ return newExitCodeError(1)
+ case 2:
+ return newExitCodeError(2)
+ default:
+ t.Fatalf("unexpected command: %#v", cmd)
+ return nil
+ }
+ }
+ exitCode := callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, mainCc))
+ if exitCode != 2 {
+ t.Errorf("unexpected exit code. Got: %d", exitCode)
+ }
+ })
+}
+
+func TestForwardStdinToFallbackCompile(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
+ stdinStr := ctx.readAllString(stdin)
+ if stdinStr != "someinput" {
+ return fmt.Errorf("unexpected stdin. Got: %s", stdinStr)
+ }
+
+ switch ctx.cmdCount {
+ case 1:
+ return newExitCodeError(1)
+ case 2:
+ return nil
+ default:
+ t.Fatalf("unexpected command: %#v", cmd)
+ return nil
+ }
+ }
+ io.WriteString(&ctx.stdinBuffer, "someinput")
+ ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, "-", mainCc)))
+ })
+}
+
+func TestCompileWithFallbackExtraArgs(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ testData := []struct {
+ compiler string
+ expectExtraArgs bool
+ }{
+ {"./clang", true},
+ {"./clang++", true},
+ {"./some_clang", false},
+ }
+ ctx.env = append(ctx.env, "ANDROID_LLVM_FALLBACK_DISABLED_WARNINGS=-a -b")
+ extraArgs := []string{"-fno-color-diagnostics", "-a", "-b"}
+ for _, tt := range testData {
+ ctx.cmdCount = 0
+ ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
+ switch ctx.cmdCount {
+ case 1:
+ if tt.expectExtraArgs {
+ if err := verifyArgOrder(cmd, extraArgs...); err != nil {
+ return err
+ }
+ } else {
+ for _, arg := range extraArgs {
+ if err := verifyArgCount(cmd, 0, arg); err != nil {
+ return err
+ }
+ }
+ }
+ return newExitCodeError(1)
+ case 2:
+ for _, arg := range extraArgs {
+ if err := verifyArgCount(cmd, 0, arg); err != nil {
+ return err
+ }
+ }
+ return nil
+ default:
+ t.Fatalf("unexpected command: %#v", cmd)
+ return nil
+ }
+ }
+ ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(tt.compiler, mainCc)))
+ if ctx.cmdCount != 2 {
+ t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount)
+ }
+ }
+ })
+}
+
+func TestCompileWithFallbackLogCommandAndErrors(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ ctx.env = append(ctx.env, "ANDROID_LLVM_FALLBACK_DISABLED_WARNINGS=-a -b")
+ ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
+ switch ctx.cmdCount {
+ case 1:
+ fmt.Fprint(stderr, "someerror\n")
+ return newExitCodeError(1)
+ case 2:
+ return nil
+ default:
+ t.Fatalf("unexpected command: %#v", cmd)
+ return nil
+ }
+ }
+ ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, mainCc)))
+
+ log := readCompileWithFallbackErrorLog(ctx)
+ if log != `==================COMMAND:====================
+clang.real main.cc -fno-color-diagnostics -a -b
+
+someerror
+==============================================
+
+` {
+ t.Errorf("unexpected log. Got: %s", log)
+ }
+
+ entry, _ := os.Lstat(filepath.Join(ctx.tempDir, "fallback_stderr"))
+ if entry.Mode()&0777 != 0644 {
+ t.Errorf("unexpected mode for logfile. Got: %#o", entry.Mode())
+ }
+ })
+}
+
+func TestCompileWithFallbackAppendToLog(t *testing.T) {
+ withCompileWithFallbackTestContext(t, func(ctx *testContext) {
+ ctx.writeFile(filepath.Join(ctx.tempDir, "fallback_stderr"), "oldContent\n")
+ ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
+ switch ctx.cmdCount {
+ case 1:
+ return newExitCodeError(1)
+ case 2:
+ return nil
+ default:
+ t.Fatalf("unexpected command: %#v", cmd)
+ return nil
+ }
+ }
+ ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangAndroid, mainCc)))
+
+ log := readCompileWithFallbackErrorLog(ctx)
+ if !strings.Contains(log, "oldContent") {
+ t.Errorf("old content not present: %s", log)
+ }
+ if !strings.Contains(log, "clang.real") {
+ t.Errorf("new content not present: %s", log)
+ }
+ })
+}
+
+func withCompileWithFallbackTestContext(t *testing.T, work func(ctx *testContext)) {
+ withTestContext(t, func(ctx *testContext) {
+ ctx.cfg.isAndroidWrapper = true
+ ctx.env = []string{
+ "ANDROID_LLVM_PREBUILT_COMPILER_PATH=fallback_compiler",
+ "ANDROID_LLVM_STDERR_REDIRECT=" + filepath.Join(ctx.tempDir, "fallback_stderr"),
+ }
+ work(ctx)
+ })
+}
+
+func readCompileWithFallbackErrorLog(ctx *testContext) string {
+ logFile := filepath.Join(ctx.tempDir, "fallback_stderr")
+ data, err := ioutil.ReadFile(logFile)
+ if err != nil {
+ ctx.t.Fatalf("error reading log file %s: %s", logFile, err)
+ }
+ return string(data)
+}