aboutsummaryrefslogtreecommitdiff
path: root/tests/core/strip/strip_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'tests/core/strip/strip_test.go')
-rw-r--r--tests/core/strip/strip_test.go270
1 files changed, 270 insertions, 0 deletions
diff --git a/tests/core/strip/strip_test.go b/tests/core/strip/strip_test.go
new file mode 100644
index 00000000..b7183033
--- /dev/null
+++ b/tests/core/strip/strip_test.go
@@ -0,0 +1,270 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package strip_test
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+go_binary(
+ name = "strip",
+ srcs = ["strip.go"],
+)
+-- strip.go --
+package main
+
+import (
+ "debug/elf"
+ "debug/macho"
+ "debug/pe"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "regexp"
+ "runtime"
+ "runtime/debug"
+ "strings"
+)
+
+var wantStrip = flag.Bool("wantstrip", false, "")
+
+func main() {
+ flag.Parse()
+ stackTrace, err := panicAndRecover()
+ if err != nil {
+ panic(err)
+ }
+ gotStackTrace := strings.Split(stackTrace, "\n")
+ if len(gotStackTrace) != len(wantStackTrace) {
+ panic(fmt.Sprintf("got %d lines of stack trace, want %d", len(gotStackTrace), len(wantStackTrace)))
+ }
+ for i := range gotStackTrace {
+ expectedLine := regexp.MustCompile(wantStackTrace[i])
+ if !expectedLine.MatchString(gotStackTrace[i]) {
+ panic(fmt.Sprintf("got unexpected stack trace line %q at index %d", gotStackTrace[i], i))
+ }
+ }
+ stripped, err := isStripped()
+ if err != nil {
+ panic(err)
+ }
+ if stripped != *wantStrip {
+ panic(fmt.Sprintf("got stripped=%t, want stripped=%t", stripped, *wantStrip))
+ }
+}
+
+func panicAndRecover() (stackTrace string, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ stackTrace = string(debug.Stack())
+ }
+ }()
+ panic("test")
+ return "", errors.New("should not reach here")
+}
+
+func isStripped() (bool, error) {
+ ownLocation, err := os.Executable()
+ if err != nil {
+ return false, err
+ }
+ ownBinary, err := os.Open(ownLocation)
+ if err != nil {
+ return false, err
+ }
+ defer ownBinary.Close()
+ switch runtime.GOOS {
+ case "darwin":
+ return isStrippedMachO(ownBinary)
+ case "linux":
+ return isStrippedElf(ownBinary)
+ case "windows":
+ return isStrippedPE(ownBinary)
+ default:
+ return false, fmt.Errorf("unsupported OS: %s", runtime.GOOS)
+ }
+}
+
+func isStrippedMachO(f io.ReaderAt) (bool, error) {
+ macho, err := macho.NewFile(f)
+ if err != nil {
+ return false, err
+ }
+ gotDwarf := macho.Segment("__DWARF") != nil
+ gotDebugInfo := macho.Section("__zdebug_info") != nil
+ if gotDwarf != gotDebugInfo {
+ return false, fmt.Errorf("inconsistent stripping: gotDwarf=%v, gotDebugInfo=%v", gotDwarf, gotDebugInfo)
+ }
+ return !gotDwarf, nil
+}
+
+func isStrippedElf(f io.ReaderAt) (bool, error) {
+ elf, err := elf.NewFile(f)
+ if err != nil {
+ return false, err
+ }
+ var gotSymtab bool
+ for _, section := range elf.Sections {
+ if section.Name == ".symtab" {
+ gotSymtab = true
+ break
+ }
+ }
+ return !gotSymtab, nil
+}
+
+
+func isStrippedPE(f io.ReaderAt) (bool, error) {
+ pe, err := pe.NewFile(f)
+ if err != nil {
+ return false, err
+ }
+ symtab := pe.Section(".symtab")
+ if symtab == nil {
+ return false, fmt.Errorf("no .symtab section")
+ }
+ emptySymtab := (symtab.VirtualSize <= 4) && (symtab.Size <= 512)
+ return emptySymtab, nil
+}
+
+
+` + embedWantedStackTraces(),
+ })
+}
+
+func Test(t *testing.T) {
+ for _, test := range []struct {
+ desc, stripFlag, compilationMode string
+ wantStrip bool
+ }{
+ {
+ desc: "run_auto",
+ wantStrip: true,
+ },
+ {
+ desc: "run_fastbuild",
+ compilationMode: "fastbuild",
+ wantStrip: true,
+ },
+ {
+ desc: "run_dbg",
+ compilationMode: "dbg",
+ },
+ {
+ desc: "run_opt",
+ compilationMode: "opt",
+ },
+ {
+ desc: "run_always",
+ stripFlag: "always",
+ wantStrip: true,
+ },
+ {
+ desc: "run_always_opt",
+ stripFlag: "always",
+ compilationMode: "opt",
+ wantStrip: true,
+ },
+ {
+ desc: "run_never",
+ stripFlag: "never",
+ },
+ {
+ desc: "run_sometimes_fastbuild",
+ stripFlag: "sometimes",
+ compilationMode: "fastbuild",
+ wantStrip: true,
+ },
+ {
+ desc: "run_sometimes_dbg",
+ stripFlag: "sometimes",
+ compilationMode: "dbg",
+ },
+ {
+ desc: "run_sometimes_opt",
+ stripFlag: "sometimes",
+ compilationMode: "opt",
+ },
+ } {
+ t.Run(test.desc, func(t *testing.T) {
+ args := []string{"run"}
+ if len(test.stripFlag) > 0 {
+ args = append(args, "--strip", test.stripFlag)
+ }
+ if len(test.compilationMode) > 0 {
+ args = append(args, "--compilation_mode", test.compilationMode)
+ }
+ args = append(args, "//:strip", "--", fmt.Sprintf("-wantstrip=%v", test.wantStrip))
+ cmd := bazel_testing.BazelCmd(args...)
+ stderr := &bytes.Buffer{}
+ cmd.Stderr = stderr
+ t.Logf("running: bazel %s", strings.Join(args, " "))
+ if err := cmd.Run(); err != nil {
+ var xerr *exec.ExitError
+ if !errors.As(err, &xerr) {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if xerr.ExitCode() == bazel_testing.BUILD_FAILURE {
+ t.Fatalf("unexpected build failure: %v\nstderr:\n%s", err, stderr.Bytes())
+ return
+ } else if xerr.ExitCode() == bazel_testing.TESTS_FAILED {
+ t.Fatalf("error running %s:\n%s", strings.Join(cmd.Args, " "), stderr.Bytes())
+ } else {
+ t.Fatalf("unexpected error: %v\nstderr:\n%s", err, stderr.Bytes())
+ }
+ }
+ })
+ }
+}
+
+var wantStackTrace = []string{
+ `^goroutine \d+ \[running\]:$`,
+ `^runtime/debug\.Stack\(\)$`,
+ `^ GOROOT/src/runtime/debug/stack\.go:\d+ \+0x[0-9a-f]+$`,
+ `^main\.panicAndRecover\.func1\(\)$`,
+ `^ strip\.go:\d+ \+0x[0-9a-f]+$`,
+ `^panic\({0x[0-9a-f]+, 0x[0-9a-f]+}\)$`,
+ `^ GOROOT/src/runtime/panic\.go:\d+ \+0x[0-9a-f]+$`,
+ `^main\.panicAndRecover\(\)$`,
+ `^ strip\.go:\d+ \+0x[0-9a-f]+$`,
+ `^main\.main\(\)$`,
+ `^ strip\.go:\d+ \+0x[0-9a-f]+$`,
+ `^$`,
+}
+
+func embedWantedStackTraces() string {
+ buf := &bytes.Buffer{}
+ fmt.Fprintln(buf, "var wantStackTrace = []string{")
+ for _, s := range wantStackTrace {
+ fmt.Fprintf(buf, "`%s`,\n", s)
+ }
+ fmt.Fprintln(buf, "}")
+ return buf.String()
+}