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 "bytes" 9*760c253cSXin Li "errors" 10*760c253cSXin Li "fmt" 11*760c253cSXin Li "io" 12*760c253cSXin Li "os" 13*760c253cSXin Li "path" 14*760c253cSXin Li "path/filepath" 15*760c253cSXin Li "strings" 16*760c253cSXin Li "syscall" 17*760c253cSXin Li "testing" 18*760c253cSXin Li) 19*760c253cSXin Li 20*760c253cSXin Lifunc TestAddCommonFlags(t *testing.T) { 21*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 22*760c253cSXin Li ctx.cfg.commonFlags = []string{"-someflag"} 23*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 24*760c253cSXin Li ctx.newCommand(gccX86_64, mainCc))) 25*760c253cSXin Li if err := verifyArgOrder(cmd, "-someflag", mainCc); err != nil { 26*760c253cSXin Li t.Error(err) 27*760c253cSXin Li } 28*760c253cSXin Li }) 29*760c253cSXin Li} 30*760c253cSXin Li 31*760c253cSXin Lifunc TestAddGccConfigFlags(t *testing.T) { 32*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 33*760c253cSXin Li ctx.cfg.gccFlags = []string{"-someflag"} 34*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 35*760c253cSXin Li ctx.newCommand(gccX86_64, mainCc))) 36*760c253cSXin Li if err := verifyArgOrder(cmd, "-someflag", mainCc); err != nil { 37*760c253cSXin Li t.Error(err) 38*760c253cSXin Li } 39*760c253cSXin Li }) 40*760c253cSXin Li} 41*760c253cSXin Li 42*760c253cSXin Lifunc TestAddClangConfigFlags(t *testing.T) { 43*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 44*760c253cSXin Li ctx.cfg.clangFlags = []string{"-someflag"} 45*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 46*760c253cSXin Li ctx.newCommand(clangX86_64, mainCc))) 47*760c253cSXin Li if err := verifyArgOrder(cmd, "-someflag", mainCc); err != nil { 48*760c253cSXin Li t.Error(err) 49*760c253cSXin Li } 50*760c253cSXin Li }) 51*760c253cSXin Li} 52*760c253cSXin Li 53*760c253cSXin Lifunc TestLogGeneralExecError(t *testing.T) { 54*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 55*760c253cSXin Li ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 56*760c253cSXin Li return errors.New("someerror") 57*760c253cSXin Li } 58*760c253cSXin Li stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc))) 59*760c253cSXin Li if err := verifyInternalError(stderr); err != nil { 60*760c253cSXin Li t.Fatal(err) 61*760c253cSXin Li } 62*760c253cSXin Li if !strings.Contains(stderr, gccX86_64) { 63*760c253cSXin Li t.Errorf("could not find compiler path on stderr. Got: %s", stderr) 64*760c253cSXin Li } 65*760c253cSXin Li if !strings.Contains(stderr, "someerror") { 66*760c253cSXin Li t.Errorf("could not find original error on stderr. Got: %s", stderr) 67*760c253cSXin Li } 68*760c253cSXin Li }) 69*760c253cSXin Li} 70*760c253cSXin Li 71*760c253cSXin Lifunc TestForwardStdin(t *testing.T) { 72*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 73*760c253cSXin Li io.WriteString(&ctx.stdinBuffer, "someinput") 74*760c253cSXin Li ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 75*760c253cSXin Li stdinStr := ctx.readAllString(stdin) 76*760c253cSXin Li if stdinStr != "someinput" { 77*760c253cSXin Li return fmt.Errorf("unexpected stdin. Got: %s", stdinStr) 78*760c253cSXin Li } 79*760c253cSXin Li return nil 80*760c253cSXin Li } 81*760c253cSXin Li ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, "-", mainCc))) 82*760c253cSXin Li }) 83*760c253cSXin Li} 84*760c253cSXin Li 85*760c253cSXin Lifunc TestLogMissingCCacheExecError(t *testing.T) { 86*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 87*760c253cSXin Li ctx.cfg.useCCache = true 88*760c253cSXin Li 89*760c253cSXin Li ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 90*760c253cSXin Li return syscall.ENOENT 91*760c253cSXin Li } 92*760c253cSXin Li ctx.stderrBuffer.Reset() 93*760c253cSXin Li stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc))) 94*760c253cSXin Li if err := verifyNonInternalError(stderr, "ccache not found under .*. Please install it"); err != nil { 95*760c253cSXin Li t.Fatal(err) 96*760c253cSXin Li } 97*760c253cSXin Li }) 98*760c253cSXin Li} 99*760c253cSXin Li 100*760c253cSXin Lifunc TestGomaDisablesRusage(t *testing.T) { 101*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 102*760c253cSXin Li gomaPath := path.Join(ctx.tempDir, "gomacc") 103*760c253cSXin Li ctx.writeFile(gomaPath, "") 104*760c253cSXin Li ctx.env = []string{"GOMACC_PATH=" + gomaPath} 105*760c253cSXin Li logFileName := filepath.Join(ctx.tempDir, "rusage.log") 106*760c253cSXin Li ctx.env = []string{ 107*760c253cSXin Li "TOOLCHAIN_RUSAGE_OUTPUT=" + logFileName, 108*760c253cSXin Li "GOMACC_PATH=" + gomaPath, 109*760c253cSXin Li } 110*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc))) 111*760c253cSXin Li // Ensure Goma was used 112*760c253cSXin Li if err := verifyPath(cmd, gomaPath); err != nil { 113*760c253cSXin Li t.Fatal(err) 114*760c253cSXin Li } 115*760c253cSXin Li if err := verifyArgOrder(cmd, gccX86_64+".real", mainCc); err != nil { 116*760c253cSXin Li t.Error(err) 117*760c253cSXin Li } 118*760c253cSXin Li // Ensure rusage log was not created 119*760c253cSXin Li if _, err := os.Stat(logFileName); err == nil { 120*760c253cSXin Li t.Errorf("Logfile shouldn't have been created at TOOLCHAIN_RUSAGE_OUTPUT path %q but was", logFileName) 121*760c253cSXin Li } else if !os.IsNotExist(err) { 122*760c253cSXin Li t.Fatalf("error checking for rusage logfile at %q: %v", logFileName, err) 123*760c253cSXin Li } 124*760c253cSXin Li }) 125*760c253cSXin Li} 126*760c253cSXin Li 127*760c253cSXin Lifunc TestLogRusageAndForceDisableWError(t *testing.T) { 128*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 129*760c253cSXin Li ctx.NoteTestWritesToUmask() 130*760c253cSXin Li 131*760c253cSXin Li logFileName := filepath.Join(ctx.tempDir, "rusage.log") 132*760c253cSXin Li ctx.env = []string{ 133*760c253cSXin Li "FORCE_DISABLE_WERROR=1", 134*760c253cSXin Li "TOOLCHAIN_RUSAGE_OUTPUT=" + logFileName, 135*760c253cSXin Li } 136*760c253cSXin Li ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 137*760c253cSXin Li switch ctx.cmdCount { 138*760c253cSXin Li case 1: 139*760c253cSXin Li io.WriteString(stderr, arbitraryWerrorStderr) 140*760c253cSXin Li return newExitCodeError(1) 141*760c253cSXin Li case 2: 142*760c253cSXin Li return nil 143*760c253cSXin Li default: 144*760c253cSXin Li t.Fatalf("unexpected command: %#v", cmd) 145*760c253cSXin Li return nil 146*760c253cSXin Li } 147*760c253cSXin Li } 148*760c253cSXin Li ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc))) 149*760c253cSXin Li if _, err := os.Stat(logFileName); os.IsNotExist(err) { 150*760c253cSXin Li t.Errorf("no logfile created at TOOLCHAIN_RUSAGE_OUTPUT path %q", logFileName) 151*760c253cSXin Li } else if err != nil { 152*760c253cSXin Li t.Fatalf("error checking for rusage logfile at %q: %v", logFileName, err) 153*760c253cSXin Li } 154*760c253cSXin Li if ctx.cmdCount != 2 { 155*760c253cSXin Li t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount) 156*760c253cSXin Li } 157*760c253cSXin Li }) 158*760c253cSXin Li} 159*760c253cSXin Li 160*760c253cSXin Lifunc TestErrorOnLogRusageAndBisect(t *testing.T) { 161*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 162*760c253cSXin Li ctx.NoteTestWritesToUmask() 163*760c253cSXin Li 164*760c253cSXin Li ctx.env = []string{ 165*760c253cSXin Li "BISECT_STAGE=xyz", 166*760c253cSXin Li "TOOLCHAIN_RUSAGE_OUTPUT=rusage.log", 167*760c253cSXin Li } 168*760c253cSXin Li stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc))) 169*760c253cSXin Li if err := verifyNonInternalError(stderr, "TOOLCHAIN_RUSAGE_OUTPUT is meaningless with BISECT_STAGE"); err != nil { 170*760c253cSXin Li t.Error(err) 171*760c253cSXin Li } 172*760c253cSXin Li }) 173*760c253cSXin Li} 174*760c253cSXin Li 175*760c253cSXin Lifunc TestErrorOnBisectAndForceDisableWError(t *testing.T) { 176*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 177*760c253cSXin Li ctx.NoteTestWritesToUmask() 178*760c253cSXin Li 179*760c253cSXin Li ctx.env = []string{ 180*760c253cSXin Li "BISECT_STAGE=xyz", 181*760c253cSXin Li "FORCE_DISABLE_WERROR=1", 182*760c253cSXin Li } 183*760c253cSXin Li stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc))) 184*760c253cSXin Li if err := verifyNonInternalError(stderr, "BISECT_STAGE is meaningless with FORCE_DISABLE_WERROR"); err != nil { 185*760c253cSXin Li t.Error(err) 186*760c253cSXin Li } 187*760c253cSXin Li }) 188*760c253cSXin Li} 189*760c253cSXin Li 190*760c253cSXin Lifunc TestPrintUserCompilerError(t *testing.T) { 191*760c253cSXin Li buffer := bytes.Buffer{} 192*760c253cSXin Li printCompilerError(&buffer, newUserErrorf("abcd")) 193*760c253cSXin Li if buffer.String() != "abcd\n" { 194*760c253cSXin Li t.Errorf("Unexpected string. Got: %s", buffer.String()) 195*760c253cSXin Li } 196*760c253cSXin Li} 197*760c253cSXin Li 198*760c253cSXin Lifunc TestPrintOtherCompilerError(t *testing.T) { 199*760c253cSXin Li buffer := bytes.Buffer{} 200*760c253cSXin Li printCompilerError(&buffer, errors.New("abcd")) 201*760c253cSXin Li if buffer.String() != "Internal error. Please report to [email protected].\nabcd\n" { 202*760c253cSXin Li t.Errorf("Unexpected string. Got: %s", buffer.String()) 203*760c253cSXin Li } 204*760c253cSXin Li} 205*760c253cSXin Li 206*760c253cSXin Lifunc TestPrintOtherCompilerErrorForAndroidLLVM(t *testing.T) { 207*760c253cSXin Li buffer := bytes.Buffer{} 208*760c253cSXin Li 209*760c253cSXin Li oldConfigName := ConfigName 210*760c253cSXin Li defer func() { ConfigName = oldConfigName }() 211*760c253cSXin Li 212*760c253cSXin Li ConfigName = "android" 213*760c253cSXin Li printCompilerError(&buffer, errors.New("abcd")) 214*760c253cSXin Li if buffer.String() != "Internal error. Please report to [email protected].\nabcd\n" { 215*760c253cSXin Li t.Errorf("Unexpected string. Got: %s", buffer.String()) 216*760c253cSXin Li } 217*760c253cSXin Li} 218*760c253cSXin Li 219*760c253cSXin Lifunc TestCalculateAndroidWrapperPath(t *testing.T) { 220*760c253cSXin Li t.Parallel() 221*760c253cSXin Li 222*760c253cSXin Li testCases := []struct { 223*760c253cSXin Li mainBuilderPath string 224*760c253cSXin Li absWrapperPath string 225*760c253cSXin Li want string 226*760c253cSXin Li }{ 227*760c253cSXin Li { 228*760c253cSXin Li mainBuilderPath: "/foo/bar", 229*760c253cSXin Li absWrapperPath: "/bar/baz", 230*760c253cSXin Li want: "/foo/baz.real", 231*760c253cSXin Li }, 232*760c253cSXin Li { 233*760c253cSXin Li mainBuilderPath: "/my_wrapper", 234*760c253cSXin Li absWrapperPath: "/bar/baz", 235*760c253cSXin Li want: "/baz.real", 236*760c253cSXin Li }, 237*760c253cSXin Li { 238*760c253cSXin Li mainBuilderPath: "no_seps", 239*760c253cSXin Li absWrapperPath: "/bar/baz", 240*760c253cSXin Li want: "baz.real", 241*760c253cSXin Li }, 242*760c253cSXin Li { 243*760c253cSXin Li mainBuilderPath: "./a_sep", 244*760c253cSXin Li absWrapperPath: "/bar/baz", 245*760c253cSXin Li want: "./baz.real", 246*760c253cSXin Li }, 247*760c253cSXin Li } 248*760c253cSXin Li 249*760c253cSXin Li for _, tc := range testCases { 250*760c253cSXin Li if result := calculateAndroidWrapperPath(tc.mainBuilderPath, tc.absWrapperPath); result != tc.want { 251*760c253cSXin Li t.Errorf("Failed calculating the wrapper path with (%q, %q); got %q, want %q", tc.mainBuilderPath, tc.absWrapperPath, result, tc.want) 252*760c253cSXin Li } 253*760c253cSXin Li } 254*760c253cSXin Li} 255*760c253cSXin Li 256*760c253cSXin Li// If "crash-diagnostics-dir" flag is not provided, add one in 257*760c253cSXin Lifunc TestCrashDiagDefault(t *testing.T) { 258*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 259*760c253cSXin Li ctx.env = []string{ 260*760c253cSXin Li "CROS_ARTIFACTS_TMP_DIR=/tmp/foo", 261*760c253cSXin Li } 262*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 263*760c253cSXin Li ctx.newCommand(clangX86_64, mainCc))) 264*760c253cSXin Li 265*760c253cSXin Li // Verify that we added the default flag 266*760c253cSXin Li if err := verifyArgCount(cmd, 1, "-fcrash-diagnostics-dir=/tmp/foo/toolchain/clang_crash_diagnostics"); err != nil { 267*760c253cSXin Li t.Error(err) 268*760c253cSXin Li } 269*760c253cSXin Li }) 270*760c253cSXin Li} 271*760c253cSXin Li 272*760c253cSXin Li// If "crash-diagnostics-dir" flag is already provided by the user, only use that flag and don't add a dupe 273*760c253cSXin Lifunc TestCrashDiagUserFlag(t *testing.T) { 274*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 275*760c253cSXin Li ctx.env = []string{ 276*760c253cSXin Li "CROS_ARTIFACTS_TMP_DIR=/tmp/foo", 277*760c253cSXin Li } 278*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 279*760c253cSXin Li ctx.newCommand(clangX86_64, mainCc, "-fcrash-diagnostics-dir=/build/something/foozz"))) 280*760c253cSXin Li 281*760c253cSXin Li // Verify that user flag is not removed 282*760c253cSXin Li if err := verifyArgCount(cmd, 1, "-fcrash-diagnostics-dir=/build/something/foozz"); err != nil { 283*760c253cSXin Li t.Error(err) 284*760c253cSXin Li } 285*760c253cSXin Li 286*760c253cSXin Li // Verify that we did not add the default flag 287*760c253cSXin Li if err := verifyArgCount(cmd, 0, "-fcrash-diagnostics-dir=/tmp/foo/toolchain/clang_crash_diagnostics"); err != nil { 288*760c253cSXin Li t.Error(err) 289*760c253cSXin Li } 290*760c253cSXin Li }) 291*760c253cSXin Li} 292