1// Copyright 2019 The ChromiumOS Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package main 6 7import ( 8 "encoding/json" 9 "errors" 10 "fmt" 11 "io" 12 "io/ioutil" 13 "os" 14 "path/filepath" 15 "regexp" 16 "strings" 17 "testing" 18) 19 20func TestForwardStdOutAndStdErrAndExitCodeFromLogRusage(t *testing.T) { 21 withLogRusageTestContext(t, func(ctx *testContext) { 22 ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 23 fmt.Fprint(stdout, "somemessage") 24 fmt.Fprint(stderr, "someerror") 25 return newExitCodeError(23) 26 } 27 exitCode := callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc)) 28 if exitCode != 23 { 29 t.Errorf("unexpected exit code. Got: %d", exitCode) 30 } 31 if ctx.stdoutString() != "somemessage" { 32 t.Errorf("stdout was not forwarded. Got: %s", ctx.stdoutString()) 33 } 34 if ctx.stderrString() != "someerror" { 35 t.Errorf("stderr was not forwarded. Got: %s", ctx.stderrString()) 36 } 37 }) 38} 39 40func TestForwardStdinFromLogRusage(t *testing.T) { 41 withLogRusageTestContext(t, func(ctx *testContext) { 42 ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 43 // Note: This is called for the clang syntax call as well as for 44 // the gcc call, and we assert that stdin is cloned and forwarded 45 // to both. 46 stdinStr := ctx.readAllString(stdin) 47 if stdinStr != "someinput" { 48 return fmt.Errorf("unexpected stdin. Got: %s", stdinStr) 49 } 50 return nil 51 } 52 io.WriteString(&ctx.stdinBuffer, "someinput") 53 ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(clangX86_64, "-", mainCc))) 54 }) 55} 56 57func TestReportGeneralErrorsFromLogRusage(t *testing.T) { 58 withLogRusageTestContext(t, func(ctx *testContext) { 59 ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 60 return errors.New("someerror") 61 } 62 stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, 63 ctx.newCommand(gccX86_64, mainCc))) 64 if err := verifyInternalError(stderr); err != nil { 65 t.Fatal(err) 66 } 67 if !strings.Contains(stderr, "someerror") { 68 t.Errorf("unexpected error. Got: %s", stderr) 69 } 70 }) 71} 72 73func TestCreateDirAndFileForLogRusage(t *testing.T) { 74 withLogRusageTestContext(t, func(ctx *testContext) { 75 logFileName := filepath.Join(ctx.tempDir, "somedir", "rusage.log") 76 ctx.env = []string{"TOOLCHAIN_RUSAGE_OUTPUT=" + logFileName} 77 ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc))) 78 79 if _, err := os.Stat(logFileName); err != nil { 80 t.Errorf("rusage log file does not exist: %s", err) 81 } 82 }) 83} 84 85func TestLogRusageFileContent(t *testing.T) { 86 withLogRusageTestContext(t, func(ctx *testContext) { 87 logFileName := filepath.Join(ctx.tempDir, "rusage.log") 88 ctx.env = []string{"TOOLCHAIN_RUSAGE_OUTPUT=" + logFileName} 89 ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc))) 90 91 data, err := ioutil.ReadFile(logFileName) 92 if err != nil { 93 t.Errorf("could not read the rusage log file. Error: %s", err) 94 } 95 96 rlog := rusageLog{} 97 98 if err := json.Unmarshal(data, &rlog); err != nil { 99 t.Fatalf("rusage log could not be unmarshalled. Got: %s", data) 100 } 101 102 if rlog.Compiler != filepath.Join(ctx.tempDir, gccX86_64+".real") { 103 t.Errorf("unexpected compiler path. Got: %s", rlog.Compiler) 104 } 105 if matched, _ := regexp.MatchString("--sysroot=.*", rlog.CompilerArgs[0]); !matched { 106 t.Errorf("unexpected compiler args. Got: %s", rlog.CompilerArgs) 107 } 108 cwd, err := os.Getwd() 109 if err != nil { 110 t.Fatalf("Failed to get current working directory: %v", err) 111 } 112 if rlog.WorkingDirectory != cwd { 113 t.Errorf("Unexpected working directory. Got: %q, Want: %q", rlog.WorkingDirectory, cwd) 114 } 115 }) 116} 117 118func TestLogRusageAppendsToFile(t *testing.T) { 119 withLogRusageTestContext(t, func(ctx *testContext) { 120 logFileName := filepath.Join(ctx.tempDir, "rusage.log") 121 ctx.env = []string{"TOOLCHAIN_RUSAGE_OUTPUT=" + logFileName} 122 123 ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc))) 124 data, err := ioutil.ReadFile(logFileName) 125 if err != nil { 126 t.Errorf("could not read the rusage log file. Error: %s", err) 127 } 128 firstCallLines := strings.Split(string(data), "\n") 129 if len(firstCallLines) != 2 { 130 t.Errorf("unexpected number of lines. Got: %s", firstCallLines) 131 } 132 if firstCallLines[0] == "" { 133 t.Error("first line was empty") 134 } 135 if firstCallLines[1] != "" { 136 t.Errorf("second line was not empty. Got: %s", firstCallLines[1]) 137 } 138 139 ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc))) 140 data, err = ioutil.ReadFile(logFileName) 141 if err != nil { 142 t.Errorf("could not read the rusage log file. Error: %s", err) 143 } 144 secondCallLines := strings.Split(string(data), "\n") 145 if len(secondCallLines) != 3 { 146 t.Errorf("unexpected number of lines. Got: %s", secondCallLines) 147 } 148 if secondCallLines[0] != firstCallLines[0] { 149 t.Errorf("first line was changed. Got: %s", secondCallLines[0]) 150 } 151 if secondCallLines[1] == "" { 152 t.Error("second line was empty") 153 } 154 if secondCallLines[2] != "" { 155 t.Errorf("third line was not empty. Got: %s", secondCallLines[2]) 156 } 157 }) 158} 159 160func withLogRusageTestContext(t *testing.T, work func(ctx *testContext)) { 161 withTestContext(t, func(ctx *testContext) { 162 ctx.NoteTestWritesToUmask() 163 164 ctx.env = []string{"TOOLCHAIN_RUSAGE_OUTPUT=" + filepath.Join(ctx.tempDir, "rusage.log")} 165 work(ctx) 166 }) 167} 168