diff --git a/go/tools/bazel_testing/bazel_testing.go b/go/tools/bazel_testing/bazel_testing.go index 54c0090f4f..f9dbeff1ac 100644 --- a/go/tools/bazel_testing/bazel_testing.go +++ b/go/tools/bazel_testing/bazel_testing.go @@ -189,6 +189,30 @@ func RunBazel(args ...string) error { return err } +// BazelInfo collects the workspace attributes and returns them. +// +// If the command starts but exits with a non-zero status, a *StderrExitError +// will be returned which wraps the original *exec.ExitError. +func BazelInfo() (map[string]string, error) { + out, err := BazelOutput("info") + return parseInfo(out), err +} + +func parseInfo(in []byte) map[string]string { + ret := map[string]string{} + + lines := bytes.Split(in, []byte("\n")) + for _, line := range lines { + if len(line) == 0 { + continue + } + res := bytes.SplitN(line, []byte(": "), 2) + ret[string(res[0])] = string(res[1]) + } + + return ret +} + // BazelOutput invokes a bazel command with a list of arguments and returns // the content of stdout. // diff --git a/go/tools/bazel_testing/bazel_testing_test.go b/go/tools/bazel_testing/bazel_testing_test.go new file mode 100644 index 0000000000..1442b990a8 --- /dev/null +++ b/go/tools/bazel_testing/bazel_testing_test.go @@ -0,0 +1,9 @@ +package bazel_testing + +import ( + "testing" +) + +func TestParseInfo(t *testing.T) { + +} diff --git a/tests/core/stamp/BUILD.bazel b/tests/core/stamp/BUILD.bazel new file mode 100644 index 0000000000..06a3ae756d --- /dev/null +++ b/tests/core/stamp/BUILD.bazel @@ -0,0 +1,6 @@ +load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test") + +go_bazel_test( + name = "genrule_go_binary_test", + srcs = ["genrule_go_binary_test.go"], +) diff --git a/tests/core/stamp/README.rst b/tests/core/stamp/README.rst new file mode 100644 index 0000000000..86c7c4eafc --- /dev/null +++ b/tests/core/stamp/README.rst @@ -0,0 +1,10 @@ +.. _#2224: https://github.com/bazelbuild/rules_go/issues/2224 + +Stamp functionality +=================== + +genrule_go_binary +----------------- + +Checks that ``go_binary`` targets depended upon by genrules are stamped. +This is just a regression test for (`#2224`_). diff --git a/tests/core/stamp/fileset_stamp_go_binary_test.go b/tests/core/stamp/fileset_stamp_go_binary_test.go new file mode 100644 index 0000000000..de594a7862 --- /dev/null +++ b/tests/core/stamp/fileset_stamp_go_binary_test.go @@ -0,0 +1,132 @@ +// 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 fileset_stamp_go_binary_test + +import ( + "bytes" + "io/ioutil" + "os" + "os/exec" + "strings" + "testing" + + "github.com/bazelbuild/rules_go/go/tools/bazel" + "github.com/bazelbuild/rules_go/go/tools/bazel_testing" +) + +const ( + genruleOut = "genrule_out" + successMsg = "success" + stampNotAppliedMsg = "Stamp == stampNotApplied" + stampNotEvaluatedMsg = "Stamp == setButUnevaluated" +) + +func TestMain(m *testing.M) { + bazel_testing.TestMain(m, bazel_testing.Args{ + Main: ` +-- .bazelrc -- +build:stamp --stamp +build:stamp --workspace_status_command="sh status.sh" +# Note that run and test both inherrit bazelrc options from build +-- status.sh -- +echo "STABLE_STAMPED_VARIABLE ` + successMsg + `" +-- BUILD.bazel -- +load("@io_bazel_rules_go//go:def.bzl", "go_binary") +go_binary( + name = "stamp", + srcs = ["stamp.go"], + out = "stamp", + x_defs = { + "main.stamp": "{STABLE_STAMPED_VARIABLE}", + }, +) +filegroup( + name = "filegroup", + srcs = [":stamp"], +) +-- stamp.go -- +package main + +import "fmt" + +const setButUnevaluated = "{STABLE_STAMPED_VARIABLE}" +const stampNotApplied = "STAMP_NOT_APPLIED" + +var stamp string = stampNotApplied + +func main() { + fmt.Print(stamp) +} +`, + }) +} + +func Test(t *testing.T) { + // Running the go binary without stamping should cause the stampNotAppliedMsg error. + if err := bazel_testing.RunBazel( + "build", + "//:filegroup", + ); err == nil { + // This is good + } else if bErr, ok := err.(*bazel_testing.StderrExitError); !ok { + t.Fatalf("got %v; want StderrExitError", err) + } else if code := bErr.Err.ExitCode(); code != 2 { + t.Fatalf("got code %d; want code 2 (test failure)\n%v", code, bErr.Error()) + } else if !strings.Contains(bErr.Error(), stampNotEvaluatedMsg) { + t.Fatalf("got %q; should contain %q", bErr.Error(), stampNotEvaluatedMsg) + } + + cmd := exec.Command("find", "./bazel-bin/") + cmd.Stdout = os.Stdout + cmd.Run() + + // Run the binary that was included in the filegroup to see if the output contains "success" + bin, ok := bazel.FindBinary("filegroup", "stamp") + if !ok { + t.Fatal("bazel.FindBinary(\"filegroup\", \"stamp\") = false") + } + t.Log(bin) + + // Build the genrule that has the stamped binary transitively. + if err := bazel_testing.RunBazel( + "build", + "--config=stamp", + "//:genrule", + ); err != nil { + t.Fatal(err) + } + + var genruleFilePath string + if info, err := bazel_testing.BazelInfo(); err != nil { + t.Fatal(err) + } else { + genruleFilePath = info["output_path"] + } + + files, err := ioutil.ReadDir(genruleFilePath) + if err != nil { + t.Fatal(err) + } + + for _, file := range files { + t.Logf("File: %s", file.Name()) + } + + if output, err := ioutil.ReadFile(genruleFilePath + "/" + genruleOut); err != nil { + t.Fatal(err) + } else if !bytes.Equal(output, []byte(successMsg)) { + t.Fatalf("got %q; want %q", output, successMsg) + } +} diff --git a/tests/core/stamp/genrule_go_binary_test.go b/tests/core/stamp/genrule_go_binary_test.go new file mode 100644 index 0000000000..46037e1145 --- /dev/null +++ b/tests/core/stamp/genrule_go_binary_test.go @@ -0,0 +1,128 @@ +// 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 genrule_go_binary_test + +import ( + "bytes" + "io/ioutil" + "strings" + "testing" + + "github.com/bazelbuild/rules_go/go/tools/bazel_testing" +) + +const ( + genruleOut = "genrule_out" + successMsg = "success" + stampNotAppliedMsg = "Stamp == stampNotApplied" + stampNotEvaluatedMsg = "Stamp == setButUnevaluated" +) + +func TestMain(m *testing.M) { + bazel_testing.TestMain(m, bazel_testing.Args{ + Main: ` +-- .bazelrc -- +build:stamp --stamp +build:stamp --workspace_status_command="sh status.sh" +# Note that run and test both inherrit bazelrc options from build +-- status.sh -- +echo "STABLE_STAMPED_VARIABLE ` + successMsg + `" +-- BUILD.bazel -- +load("@io_bazel_rules_go//go:def.bzl", "go_binary") +go_binary( + name = "stamp", + srcs = ["stamp.go"], + out = "stamp", + x_defs = { + "main.stamp": "{STABLE_STAMPED_VARIABLE}", + }, +) +genrule( + name = "genrule", + cmd = "$(location :stamp) > $@", + tools = [":stamp"], + outs = ["` + genruleOut + `"], +) +-- stamp.go -- +package main + +import "fmt" + +const setButUnevaluated = "{STABLE_STAMPED_VARIABLE}" +const stampNotApplied = "STAMP_NOT_APPLIED" + +var stamp string = stampNotApplied + +func main() { + if stamp == stampNotApplied { + panic("` + stampNotAppliedMsg + `") + } + // TODO(issue/2224): Uncomment this line to demonstrate stamping issues. + //if stamp == setButUnevaluated { + // panic("` + stampNotEvaluatedMsg + `") + //} + //fmt.Print(stamp) + fmt.Print("` + successMsg + `") +} +`, + }) +} + +func Test(t *testing.T) { + // Running the go binary without stamping should cause the stampNotAppliedMsg error. + if err := bazel_testing.RunBazel( + "run", + "//:stamp", + ); err == nil { + //t.Fatal("got success; want failure") + } else if bErr, ok := err.(*bazel_testing.StderrExitError); !ok { + t.Fatalf("got %v; want StderrExitError", err) + } else if code := bErr.Err.ExitCode(); code != 2 { + t.Fatalf("got code %d; want code 2 (test failure)\n%v", code, bErr.Error()) + } else if !strings.Contains(bErr.Error(), stampNotEvaluatedMsg) { + t.Fatalf("got %q; should contain %q", bErr.Error(), stampNotEvaluatedMsg) + } + + // Running the go binary with stamping should work just fine. + if err := bazel_testing.RunBazel( + "run", + "--config=stamp", + "//:stamp", + ); err != nil { + t.Fatal(err) + } + + // Build the genrule that has the stamped binary transitively. + if err := bazel_testing.RunBazel( + "build", + "--config=stamp", + "//:genrule", + ); err != nil { + t.Fatal(err) + } + + var genruleFilePath string + if info, err := bazel_testing.BazelInfo(); err != nil { + t.Fatal(err) + } else { + genruleFilePath = info["bazel-bin"] + } + + if output, err := ioutil.ReadFile(genruleFilePath + "/" + genruleOut); err != nil { + t.Fatal(err) + } else if !bytes.Equal(output, []byte(successMsg)) { + t.Fatalf("got %q; want %q", output, successMsg) + } +}