aboutsummaryrefslogtreecommitdiff
path: root/tests/core/transition/hermeticity_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'tests/core/transition/hermeticity_test.go')
-rw-r--r--tests/core/transition/hermeticity_test.go289
1 files changed, 289 insertions, 0 deletions
diff --git a/tests/core/transition/hermeticity_test.go b/tests/core/transition/hermeticity_test.go
new file mode 100644
index 00000000..08eda7d6
--- /dev/null
+++ b/tests/core/transition/hermeticity_test.go
@@ -0,0 +1,289 @@
+// Copyright 2021 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 hermeticity_test
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "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_library", "go_test")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+load("@rules_proto//proto:defs.bzl", "proto_library")
+
+go_binary(
+ name = "main",
+ srcs = [
+ "main.go",
+ ":gen_go",
+ ],
+ data = [":helper"],
+ embedsrcs = [":helper"],
+ cdeps = [":helper"],
+ cgo = True,
+ linkmode = "c-archive",
+ gotags = ["foo"],
+ deps = [":lib"],
+)
+
+go_library(
+ name = "lib",
+ srcs = [
+ "lib.go",
+ ":gen_indirect_go",
+ ],
+ importpath = "example.com/lib",
+ data = [":indirect_helper"],
+ embedsrcs = [":indirect_helper"],
+ cdeps = [":indirect_helper"],
+ cgo = True,
+)
+
+go_test(
+ name = "main_test",
+ srcs = [
+ "main.go",
+ ":gen_go",
+ ],
+ data = [":helper"],
+ embedsrcs = [":helper"],
+ cdeps = [":helper"],
+ cgo = True,
+ linkmode = "c-archive",
+ gotags = ["foo"],
+)
+
+cc_library(
+ name = "helper",
+)
+
+cc_library(
+ name = "indirect_helper",
+)
+
+genrule(
+ name = "gen_go",
+ outs = ["gen.go"],
+ exec_tools = [":helper"],
+ cmd = "# Not needed for bazel cquery",
+)
+
+genrule(
+ name = "gen_indirect_go",
+ outs = ["gen_indirect.go"],
+ exec_tools = [":indirect_helper"],
+ cmd = "# Not needed for bazel cquery",
+)
+
+proto_library(
+ name = "foo_proto",
+ srcs = ["foo.proto"],
+)
+
+go_proto_library(
+ name = "foo_go_proto",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/transition/foo",
+ proto = ":foo_proto",
+)
+-- main.go --
+package main
+
+func main() {}
+-- lib.go --
+-- foo.proto --
+syntax = "proto3";
+
+package tests.core.transition.foo;
+option go_package = "github.com/bazelbuild/rules_go/tests/core/transition/foo";
+
+message Foo {
+ int64 value = 1;
+}
+`,
+ WorkspaceSuffix: `
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
+ name = "com_google_protobuf",
+ sha256 = "75be42bd736f4df6d702a0e4e4d30de9ee40eac024c4b845d17ae4cc831fe4ae",
+ strip_prefix = "protobuf-21.7",
+ # latest available in BCR, as of 2022-09-30
+ urls = [
+ "https://github.com/protocolbuffers/protobuf/archive/v21.7.tar.gz",
+ "https://mirror.bazel.build/github.com/protocolbuffers/protobuf/archive/v21.7.tar.gz",
+ ],
+)
+
+load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
+
+protobuf_deps()
+
+http_archive(
+ name = "rules_proto",
+ sha256 = "4d421d51f9ecfe9bf96ab23b55c6f2b809cbaf0eea24952683e397decfbd0dd0",
+ strip_prefix = "rules_proto-f6b8d89b90a7956f6782a4a3609b2f0eee3ce965",
+ # master, as of 2020-01-06
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/f6b8d89b90a7956f6782a4a3609b2f0eee3ce965.tar.gz",
+ "https://github.com/bazelbuild/rules_proto/archive/f6b8d89b90a7956f6782a4a3609b2f0eee3ce965.tar.gz",
+ ],
+)
+`,
+ })
+}
+
+func TestGoBinaryNonGoAttrsAreReset(t *testing.T) {
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:main",
+ "//:helper")
+}
+
+func TestGoLibraryNonGoAttrsAreReset(t *testing.T) {
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:main",
+ "//:indirect_helper")
+}
+
+func TestGoTestNonGoAttrsAreReset(t *testing.T) {
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:main_test",
+ "//:helper")
+}
+
+func TestGoProtoLibraryToolAttrsAreReset(t *testing.T) {
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:foo_go_proto",
+ "@com_google_protobuf//:protoc",
+ "--@io_bazel_rules_go//go/config:static",
+ "--@io_bazel_rules_go//go/config:msan",
+ "--@io_bazel_rules_go//go/config:race",
+ "--@io_bazel_rules_go//go/config:debug",
+ "--@io_bazel_rules_go//go/config:linkmode=c-archive",
+ "--@io_bazel_rules_go//go/config:tags=fake_tag",
+ )
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:foo_go_proto",
+ "@com_google_protobuf//:protoc",
+ "--@io_bazel_rules_go//go/config:pure",
+ )
+}
+
+func assertDependsCleanlyOnWithFlags(t *testing.T, targetA, targetB string, flags ...string) {
+ query := fmt.Sprintf("deps(%s) intersect %s", targetA, targetB)
+ out, err := bazel_testing.BazelOutput(append(
+ []string{
+ "cquery",
+ "--transitions=full",
+ "--output=jsonproto",
+ query,
+ },
+ flags...,
+ )...,
+ )
+ if err != nil {
+ t.Fatalf("bazel cquery '%s': %v", query, err)
+ }
+ cqueryOut := bytes.TrimSpace(out)
+ configHashes := extractConfigHashes(t, cqueryOut)
+ if len(configHashes) != 1 {
+ differingGoOptions := getGoOptions(t, configHashes...)
+ if len(differingGoOptions) != 0 {
+ t.Fatalf(
+ "%s depends on %s in multiple configs with these differences in rules_go options: %s",
+ targetA,
+ targetB,
+ strings.Join(differingGoOptions, "\n"),
+ )
+ }
+ }
+ goOptions := getGoOptions(t, configHashes[0])
+ if len(goOptions) != 0 {
+ t.Fatalf(
+ "%s depends on %s in a config with rules_go options: %s",
+ targetA,
+ targetB,
+ strings.Join(goOptions, "\n"),
+ )
+ }
+}
+
+func extractConfigHashes(t *testing.T, rawJsonOut []byte) []string {
+ var jsonOut bazelCqueryOutput
+ err := json.Unmarshal(rawJsonOut, &jsonOut)
+ if err != nil {
+ t.Fatalf("Failed to decode bazel config JSON output %v: %q", err, string(rawJsonOut))
+ }
+ var hashes []string
+ for _, result := range jsonOut.Results {
+ hashes = append(hashes, result.Configuration.Checksum)
+ }
+ return hashes
+}
+
+func getGoOptions(t *testing.T, hashes ...string) []string {
+ out, err := bazel_testing.BazelOutput(append([]string{"config", "--output=json"}, hashes...)...)
+ if err != nil {
+ t.Fatalf("bazel config %s: %v", strings.Join(hashes, " "), err)
+ }
+ rawJsonOut := bytes.TrimSpace(out)
+ var jsonOut bazelConfigOutput
+ err = json.Unmarshal(rawJsonOut, &jsonOut)
+ if err != nil {
+ t.Fatalf("Failed to decode bazel config JSON output %v: %q", err, string(rawJsonOut))
+ }
+ var differingGoOptions []string
+ for _, fragment := range jsonOut.Fragments {
+ if fragment.Name != starlarkOptionsFragment {
+ continue
+ }
+ for key, value := range fragment.Options {
+ if strings.HasPrefix(key, "@io_bazel_rules_go//") {
+ differingGoOptions = append(differingGoOptions, fmt.Sprintf("%s=%s", key, value))
+ }
+ }
+ }
+ return differingGoOptions
+}
+
+const starlarkOptionsFragment = "user-defined"
+
+type bazelConfigOutput struct {
+ Fragments []struct {
+ Name string `json:"name"`
+ Options map[string]string `json:"options"`
+ } `json:"fragmentOptions"`
+}
+
+type bazelCqueryOutput struct {
+ Results []struct {
+ Configuration struct {
+ Checksum string `json:"checksum"`
+ } `json:"configuration"`
+ } `json:"results"`
+}