diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/reproduciblebuilds_test.go')
-rw-r--r-- | src/cmd/compile/internal/gc/reproduciblebuilds_test.go | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/gc/reproduciblebuilds_test.go b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go new file mode 100644 index 0000000..8101e44 --- /dev/null +++ b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go @@ -0,0 +1,112 @@ +// Copyright 2017 The Go 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 gc_test + +import ( + "bytes" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "testing" +) + +func TestReproducibleBuilds(t *testing.T) { + tests := []string{ + "issue20272.go", + "issue27013.go", + "issue30202.go", + } + + testenv.MustHaveGoBuild(t) + iters := 10 + if testing.Short() { + iters = 4 + } + t.Parallel() + for _, test := range tests { + test := test + t.Run(test, func(t *testing.T) { + t.Parallel() + var want []byte + tmp, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("temp file creation failed: %v", err) + } + defer os.Remove(tmp.Name()) + defer tmp.Close() + for i := 0; i < iters; i++ { + // Note: use -c 2 to expose any nondeterminism which is the result + // of the runtime scheduler. + out, err := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-c", "2", "-o", tmp.Name(), filepath.Join("testdata", "reproducible", test)).CombinedOutput() + if err != nil { + t.Fatalf("failed to compile: %v\n%s", err, out) + } + obj, err := ioutil.ReadFile(tmp.Name()) + if err != nil { + t.Fatalf("failed to read object file: %v", err) + } + if i == 0 { + want = obj + } else { + if !bytes.Equal(want, obj) { + t.Fatalf("builds produced different output after %d iters (%d bytes vs %d bytes)", i, len(want), len(obj)) + } + } + } + }) + } +} + +func TestIssue38068(t *testing.T) { + testenv.MustHaveGoBuild(t) + t.Parallel() + + // Compile a small package with and without the concurrent + // backend, then check to make sure that the resulting archives + // are identical. Note: this uses "go tool compile" instead of + // "go build" since the latter will generate differnent build IDs + // if it sees different command line flags. + scenarios := []struct { + tag string + args string + libpath string + }{ + {tag: "serial", args: "-c=1"}, + {tag: "concurrent", args: "-c=2"}} + + tmpdir, err := ioutil.TempDir("", "TestIssue38068") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + src := filepath.Join("testdata", "reproducible", "issue38068.go") + for i := range scenarios { + s := &scenarios[i] + s.libpath = filepath.Join(tmpdir, s.tag+".a") + // Note: use of "-p" required in order for DWARF to be generated. + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-trimpath", "-p=issue38068", "-buildid=", s.args, "-o", s.libpath, src) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("%v: %v:\n%s", cmd.Args, err, out) + } + } + + readBytes := func(fn string) []byte { + payload, err := ioutil.ReadFile(fn) + if err != nil { + t.Fatalf("failed to read executable '%s': %v", fn, err) + } + return payload + } + + b1 := readBytes(scenarios[0].libpath) + b2 := readBytes(scenarios[1].libpath) + if !bytes.Equal(b1, b2) { + t.Fatalf("concurrent and serial builds produced different output") + } +} |