aboutsummaryrefslogtreecommitdiff
path: root/tests/integration
diff options
context:
space:
mode:
authorSpandan Das <spandandas@google.com>2023-06-15 02:30:50 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-06-15 02:30:50 +0000
commit9bb1b549b6a84214c53be0924760be030e66b93a (patch)
treed9fac15bb5a835ae6ba757dc5eaf6ef597ea44cf /tests/integration
parent9803cf8403d7105bddc1d5304d6e694b781a6605 (diff)
parent780ccd3956961690db3e36d8fa1ed7649cb0057b (diff)
downloadbazelbuild-rules_go-9bb1b549b6a84214c53be0924760be030e66b93a.tar.gz
Original change: https://android-review.googlesource.com/c/platform/external/bazelbuild-rules_go/+/2625353 Change-Id: Id4ca3195d832eca77b29b2896b89027d847bb72d Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'tests/integration')
-rw-r--r--tests/integration/README.rst23
-rw-r--r--tests/integration/gazelle/BUILD.bazel11
-rw-r--r--tests/integration/gazelle/README.rst9
-rw-r--r--tests/integration/gazelle/gazelle_test.go74
-rw-r--r--tests/integration/go_bin_runner/BUILD.bazel6
-rw-r--r--tests/integration/go_bin_runner/go_bin_runner_test.go107
-rw-r--r--tests/integration/googleapis/BUILD.bazel46
-rw-r--r--tests/integration/googleapis/README.rst8
-rw-r--r--tests/integration/googleapis/color_service.go49
-rw-r--r--tests/integration/googleapis/color_service.proto45
-rw-r--r--tests/integration/googleapis/color_service_test.go63
-rw-r--r--tests/integration/popular_repos/BUILD.bazel345
-rw-r--r--tests/integration/popular_repos/README.rst234
-rw-r--r--tests/integration/popular_repos/popular_repos.bzl75
-rwxr-xr-xtests/integration/popular_repos/popular_repos.py336
-rw-r--r--tests/integration/reproducibility/BUILD.bazel6
-rw-r--r--tests/integration/reproducibility/README.rst14
-rw-r--r--tests/integration/reproducibility/reproducibility_test.go384
18 files changed, 1835 insertions, 0 deletions
diff --git a/tests/integration/README.rst b/tests/integration/README.rst
new file mode 100644
index 00000000..0624954b
--- /dev/null
+++ b/tests/integration/README.rst
@@ -0,0 +1,23 @@
+Integration tests
+=================
+
+This folder is intended to hold larger scale test that check that rules_go
+works correctly in the real world, rather than in isolated single feature
+tests.
+
+If the unit tests were correct and exhaustive this directory should in theory
+be redundant, but in practice it helps catch many issues and points to places
+where more unit tests are needed.
+
+Contents
+--------
+
+.. Child list start
+
+* `Gazelle functionality <gazelle/README.rst>`_
+* `Popular repository tests <popular_repos/README.rst>`_
+* `Reproducibility <reproducibility/README.rst>`_
+* `Functionality related to @go_googleapis <googleapis/README.rst>`_
+
+.. Child list end
+
diff --git a/tests/integration/gazelle/BUILD.bazel b/tests/integration/gazelle/BUILD.bazel
new file mode 100644
index 00000000..90bfe2c7
--- /dev/null
+++ b/tests/integration/gazelle/BUILD.bazel
@@ -0,0 +1,11 @@
+load("//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "gazelle_test",
+ size = "medium",
+ srcs = ["gazelle_test.go"],
+ rule_files = [
+ "//:all_files",
+ "@bazel_gazelle//:all_files",
+ ],
+)
diff --git a/tests/integration/gazelle/README.rst b/tests/integration/gazelle/README.rst
new file mode 100644
index 00000000..f14f9a7d
--- /dev/null
+++ b/tests/integration/gazelle/README.rst
@@ -0,0 +1,9 @@
+Gazelle functionality
+=====================
+
+Tests that ensure rules_go still works with Gazelle.
+
+gazelle_test
+------------
+Checks that Gazelle can be run in a test workspace.
+
diff --git a/tests/integration/gazelle/gazelle_test.go b/tests/integration/gazelle/gazelle_test.go
new file mode 100644
index 00000000..42ad91db
--- /dev/null
+++ b/tests/integration/gazelle/gazelle_test.go
@@ -0,0 +1,74 @@
+// Copyright 2020 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 gazelle_test
+
+import (
+ "io/ioutil"
+ "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("@bazel_gazelle//:def.bzl", "gazelle")
+
+# gazelle:prefix example.com/hello
+gazelle(
+ name = "gazelle",
+)
+-- hello.go --
+package hello
+`,
+ WorkspaceSuffix: `
+load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
+
+gazelle_dependencies()
+`,
+ })
+}
+
+func TestUpdate(t *testing.T) {
+ if err := bazel_testing.RunBazel("run", "//:gazelle"); err != nil {
+ t.Fatal(err)
+ }
+ data, err := ioutil.ReadFile("BUILD.bazel")
+ if err != nil {
+ t.Fatal(err)
+ }
+ got := strings.TrimSpace(string(data))
+ want := strings.TrimSpace(`
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@bazel_gazelle//:def.bzl", "gazelle")
+
+# gazelle:prefix example.com/hello
+gazelle(
+ name = "gazelle",
+)
+
+go_library(
+ name = "hello",
+ srcs = ["hello.go"],
+ importpath = "example.com/hello",
+ visibility = ["//visibility:public"],
+)
+`)
+ if got != want {
+ t.Errorf("got:\n%s\n\nwant:\n%s", got, want)
+ }
+}
diff --git a/tests/integration/go_bin_runner/BUILD.bazel b/tests/integration/go_bin_runner/BUILD.bazel
new file mode 100644
index 00000000..e7db9531
--- /dev/null
+++ b/tests/integration/go_bin_runner/BUILD.bazel
@@ -0,0 +1,6 @@
+load("//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "go_bin_runner_test",
+ srcs = ["go_bin_runner_test.go"],
+)
diff --git a/tests/integration/go_bin_runner/go_bin_runner_test.go b/tests/integration/go_bin_runner/go_bin_runner_test.go
new file mode 100644
index 00000000..2cd42660
--- /dev/null
+++ b/tests/integration/go_bin_runner/go_bin_runner_test.go
@@ -0,0 +1,107 @@
+// Copyright 2023 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 go_bin_runner_test
+
+import (
+ "os"
+ "path/filepath"
+ "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 --
+sh_binary(
+ name = "go_version",
+ srcs = ["go_version.sh"],
+ env = {"GO": "$(rlocationpath @io_bazel_rules_go//go)"},
+ data = ["@io_bazel_rules_go//go"],
+ deps = ["@bazel_tools//tools/bash/runfiles"],
+)
+
+genrule(
+ name = "foo",
+ outs = ["bar"],
+ tools = ["@io_bazel_rules_go//go"],
+ cmd = "$(location @io_bazel_rules_go//go) > $@",
+)
+
+-- go_version.sh --
+# --- begin runfiles.bash initialization v2 ---
+# Copy-pasted from the Bazel Bash runfiles library v2.
+set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash
+source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
+ source "$0.runfiles/$f" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+ { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
+# --- end runfiles.bash initialization v2 ---
+
+$(rlocation "$GO") version
+`})
+}
+
+func TestGoEnv(t *testing.T) {
+ // Set an invalid GOROOT to test that the //go target still finds the expected hermetic GOROOT.
+ os.Setenv("GOROOT", "invalid")
+
+ bazelInfoOut, err := bazel_testing.BazelOutput("info", "output_base")
+ if err != nil {
+ t.Fatal(err)
+ }
+ outputBase := strings.TrimSpace(string(bazelInfoOut))
+
+ goEnvOut, err := bazel_testing.BazelOutput("run", "@io_bazel_rules_go//go", "--", "env", "GOROOT")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ goRoot := strings.TrimSpace(string(goEnvOut))
+ if goRoot != filepath.Join(outputBase, "external", "go_sdk") {
+ t.Fatalf("GOROOT was not equal to %s", filepath.Join(outputBase, "external", "go_sdk"))
+ }
+}
+
+func TestGoVersionFromScript(t *testing.T) {
+ err := os.Chmod("go_version.sh", 0755)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ goVersionOut, err := bazel_testing.BazelOutput("run", "//:go_version")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !strings.HasPrefix(string(goVersionOut), "go version go1.") {
+ t.Fatalf("go version output did not start with \"go version go1.\": %s", string(goVersionOut))
+ }
+}
+
+func TestNoGoInExec(t *testing.T) {
+ _, err := bazel_testing.BazelOutput("build", "//:foo")
+ if err == nil {
+ t.Fatal("expected build to fail")
+ }
+ stderr := string(err.(*bazel_testing.StderrExitError).Err.Stderr)
+ if !strings.Contains(stderr, "//go is only meant to be used with 'bazel run'") {
+ t.Fatalf("expected \"//go is only meant to be used with 'bazel run'\" in stderr, got %s", stderr)
+ }
+}
diff --git a/tests/integration/googleapis/BUILD.bazel b/tests/integration/googleapis/BUILD.bazel
new file mode 100644
index 00000000..53c544c6
--- /dev/null
+++ b/tests/integration/googleapis/BUILD.bazel
@@ -0,0 +1,46 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+load("@rules_proto//proto:defs.bzl", "proto_library")
+
+proto_library(
+ name = "color_service_proto",
+ srcs = ["color_service.proto"],
+ deps = [
+ "@go_googleapis//google/rpc:status_proto",
+ "@go_googleapis//google/type:color_proto",
+ ],
+)
+
+go_proto_library(
+ name = "color_service_go_proto",
+ compilers = ["@io_bazel_rules_go//proto:go_grpc"],
+ importpath = "github.com/bazelbuild/rules_go/tests/integration/googleapis/color_service_proto",
+ proto = ":color_service_proto",
+ deps = [
+ "@go_googleapis//google/rpc:status_go_proto",
+ "@go_googleapis//google/type:color_go_proto",
+ ],
+)
+
+go_library(
+ name = "color_service",
+ srcs = ["color_service.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/integration/googleapis/color_service",
+ deps = [
+ ":color_service_go_proto",
+ "@go_googleapis//google/rpc:code_go_proto",
+ "@go_googleapis//google/rpc:status_go_proto",
+ "@go_googleapis//google/type:color_go_proto",
+ ],
+)
+
+go_test(
+ name = "color_service_test",
+ srcs = ["color_service_test.go"],
+ deps = [
+ ":color_service",
+ ":color_service_go_proto",
+ "@go_googleapis//google/type:color_go_proto",
+ "@org_golang_google_grpc//:go_default_library",
+ ],
+)
diff --git a/tests/integration/googleapis/README.rst b/tests/integration/googleapis/README.rst
new file mode 100644
index 00000000..317f997e
--- /dev/null
+++ b/tests/integration/googleapis/README.rst
@@ -0,0 +1,8 @@
+Functionality related to @go_googleapis
+=======================================
+
+color_service_test
+------------------
+
+Verifies that a simple gRPC client and server can be built and run. .proto
+files are compiled at build time and depend on libraries in ``@go_googleapis``.
diff --git a/tests/integration/googleapis/color_service.go b/tests/integration/googleapis/color_service.go
new file mode 100644
index 00000000..cde3cc72
--- /dev/null
+++ b/tests/integration/googleapis/color_service.go
@@ -0,0 +1,49 @@
+// Copyright 2018 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 color_service
+
+import (
+ "context"
+ "sync"
+
+ cspb "github.com/bazelbuild/rules_go/tests/integration/googleapis/color_service_proto"
+ "google.golang.org/genproto/googleapis/rpc/code"
+ "google.golang.org/genproto/googleapis/rpc/status"
+ "google.golang.org/genproto/googleapis/type/color"
+)
+
+type colorServer struct {
+ colors sync.Map
+}
+
+func New() cspb.ColorServiceServer {
+ return &colorServer{}
+}
+
+func (s *colorServer) SetColor(ctx context.Context, r *cspb.SetColorRequest) (*cspb.SetColorResponse, error) {
+ _, loaded := s.colors.LoadOrStore(r.Name, r.Color)
+ if loaded {
+ return &cspb.SetColorResponse{Status: &status.Status{Code: int32(code.Code_ALREADY_EXISTS)}}, nil
+ }
+ return &cspb.SetColorResponse{}, nil
+}
+
+func (s *colorServer) GetColor(ctx context.Context, r *cspb.GetColorRequest) (*cspb.GetColorResponse, error) {
+ value, ok := s.colors.Load(r.Name)
+ if !ok {
+ return &cspb.GetColorResponse{Status: &status.Status{Code: int32(code.Code_NOT_FOUND)}}, nil
+ }
+ return &cspb.GetColorResponse{Color: value.(*color.Color)}, nil
+}
diff --git a/tests/integration/googleapis/color_service.proto b/tests/integration/googleapis/color_service.proto
new file mode 100644
index 00000000..6444c3bd
--- /dev/null
+++ b/tests/integration/googleapis/color_service.proto
@@ -0,0 +1,45 @@
+// Copyright 2018 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.
+
+syntax = "proto3";
+
+import "google/rpc/status.proto";
+import "google/type/color.proto";
+
+package rules_go.tests.integration.color_service;
+
+option go_package = "github.com/bazelbuild/rules_go/tests/integration/googleapis/color_service_proto";
+
+message SetColorRequest {
+ string name = 1;
+ google.type.Color color = 2;
+}
+
+message SetColorResponse {
+ google.rpc.Status status = 1;
+}
+
+message GetColorRequest {
+ string name = 1;
+}
+
+message GetColorResponse {
+ google.rpc.Status status = 1;
+ google.type.Color color = 2;
+}
+
+service ColorService {
+ rpc SetColor(SetColorRequest) returns (SetColorResponse);
+ rpc GetColor(GetColorRequest) returns (GetColorResponse);
+}
diff --git a/tests/integration/googleapis/color_service_test.go b/tests/integration/googleapis/color_service_test.go
new file mode 100644
index 00000000..f1b9ee2b
--- /dev/null
+++ b/tests/integration/googleapis/color_service_test.go
@@ -0,0 +1,63 @@
+// Copyright 2018 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 color_service_test
+
+import (
+ "context"
+ "net"
+ "reflect"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/integration/googleapis/color_service"
+ cspb "github.com/bazelbuild/rules_go/tests/integration/googleapis/color_service_proto"
+ "google.golang.org/genproto/googleapis/type/color"
+ "google.golang.org/grpc"
+)
+
+func TestColorService(t *testing.T) {
+ lis, err := net.Listen("tcp", "127.0.0.1:")
+ if err != nil {
+ t.Fatal(err)
+ }
+ grpcServer := grpc.NewServer()
+ cspb.RegisterColorServiceServer(grpcServer, color_service.New())
+ go grpcServer.Serve(lis)
+ defer grpcServer.Stop()
+
+ conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+ client := cspb.NewColorServiceClient(conn)
+
+ _, err = client.SetColor(context.Background(), &cspb.SetColorRequest{
+ Name: "red",
+ Color: &color.Color{Red: 1.0},
+ })
+ if err != nil {
+ t.Errorf("SetColor: %v", err)
+ }
+ resp, err := client.GetColor(context.Background(), &cspb.GetColorRequest{
+ Name: "red",
+ })
+ if err != nil {
+ t.Errorf("GetColor: %v", err)
+ }
+ want := &color.Color{Red: 1.0}
+ if !reflect.DeepEqual(resp.Color, want) {
+ t.Errorf("got %#v; want %#v", resp.Color, want)
+ }
+}
diff --git a/tests/integration/popular_repos/BUILD.bazel b/tests/integration/popular_repos/BUILD.bazel
new file mode 100644
index 00000000..7b92e2c8
--- /dev/null
+++ b/tests/integration/popular_repos/BUILD.bazel
@@ -0,0 +1,345 @@
+# Copyright 2017 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.
+
+##############################
+# Generated file, do not edit!
+##############################
+
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
+
+test_suite(
+ name = "org_golang_x_crypto",
+ tests = [
+ "@org_golang_x_crypto//acme:acme_test",
+ "@org_golang_x_crypto//acme/autocert:autocert_test",
+ "@org_golang_x_crypto//argon2:argon2_test",
+ "@org_golang_x_crypto//bcrypt:bcrypt_test",
+ "@org_golang_x_crypto//blake2b:blake2b_test",
+ "@org_golang_x_crypto//blake2s:blake2s_test",
+ "@org_golang_x_crypto//blowfish:blowfish_test",
+ "@org_golang_x_crypto//bn256:bn256_test",
+ "@org_golang_x_crypto//cast5:cast5_test",
+ "@org_golang_x_crypto//chacha20:chacha20_test",
+ "@org_golang_x_crypto//chacha20poly1305:chacha20poly1305_test",
+ "@org_golang_x_crypto//cryptobyte:cryptobyte_test",
+ "@org_golang_x_crypto//curve25519:curve25519_test",
+ "@org_golang_x_crypto//ed25519:ed25519_test",
+ "@org_golang_x_crypto//hkdf:hkdf_test",
+ "@org_golang_x_crypto//internal/subtle:subtle_test",
+ "@org_golang_x_crypto//md4:md4_test",
+ "@org_golang_x_crypto//nacl/auth:auth_test",
+ "@org_golang_x_crypto//nacl/box:box_test",
+ "@org_golang_x_crypto//nacl/secretbox:secretbox_test",
+ "@org_golang_x_crypto//nacl/sign:sign_test",
+ "@org_golang_x_crypto//ocsp:ocsp_test",
+ "@org_golang_x_crypto//openpgp:openpgp_test",
+ "@org_golang_x_crypto//openpgp/armor:armor_test",
+ "@org_golang_x_crypto//openpgp/clearsign:clearsign_test",
+ "@org_golang_x_crypto//openpgp/elgamal:elgamal_test",
+ "@org_golang_x_crypto//openpgp/packet:packet_test",
+ "@org_golang_x_crypto//openpgp/s2k:s2k_test",
+ "@org_golang_x_crypto//otr:otr_test",
+ "@org_golang_x_crypto//pbkdf2:pbkdf2_test",
+ "@org_golang_x_crypto//pkcs12:pkcs12_test",
+ "@org_golang_x_crypto//pkcs12/internal/rc2:rc2_test",
+ "@org_golang_x_crypto//poly1305:poly1305_test",
+ "@org_golang_x_crypto//ripemd160:ripemd160_test",
+ "@org_golang_x_crypto//salsa20:salsa20_test",
+ "@org_golang_x_crypto//salsa20/salsa:salsa_test",
+ "@org_golang_x_crypto//scrypt:scrypt_test",
+ "@org_golang_x_crypto//sha3:sha3_test",
+ "@org_golang_x_crypto//ssh/internal/bcrypt_pbkdf:bcrypt_pbkdf_test",
+ "@org_golang_x_crypto//ssh/knownhosts:knownhosts_test",
+ "@org_golang_x_crypto//tea:tea_test",
+ "@org_golang_x_crypto//twofish:twofish_test",
+ "@org_golang_x_crypto//xtea:xtea_test",
+ "@org_golang_x_crypto//xts:xts_test",
+ ],
+)
+
+test_suite(
+ name = "org_golang_x_net",
+ tests = [
+ "@org_golang_x_net//context:context_test",
+ "@org_golang_x_net//context/ctxhttp:ctxhttp_test",
+ "@org_golang_x_net//dns/dnsmessage:dnsmessage_test",
+ "@org_golang_x_net//html:html_test",
+ "@org_golang_x_net//html/atom:atom_test",
+ "@org_golang_x_net//http/httpguts:httpguts_test",
+ "@org_golang_x_net//http/httpproxy:httpproxy_test",
+ "@org_golang_x_net//http2/h2c:h2c_test",
+ "@org_golang_x_net//http2/hpack:hpack_test",
+ "@org_golang_x_net//idna:idna_test",
+ "@org_golang_x_net//internal/socks:socks_test",
+ "@org_golang_x_net//internal/sockstest:sockstest_test",
+ "@org_golang_x_net//internal/timeseries:timeseries_test",
+ "@org_golang_x_net//ipv4:ipv4_test",
+ "@org_golang_x_net//ipv6:ipv6_test",
+ "@org_golang_x_net//netutil:netutil_test",
+ "@org_golang_x_net//proxy:proxy_test",
+ "@org_golang_x_net//publicsuffix:publicsuffix_test",
+ "@org_golang_x_net//trace:trace_test",
+ "@org_golang_x_net//webdav:webdav_test",
+ "@org_golang_x_net//webdav/internal/xml:xml_test",
+ "@org_golang_x_net//websocket:websocket_test",
+ "@org_golang_x_net//xsrftoken:xsrftoken_test",
+ ],
+)
+
+test_suite(
+ name = "org_golang_x_sys",
+ tests = [
+ "@org_golang_x_sys//cpu:cpu_test",
+ "@org_golang_x_sys//execabs:execabs_test",
+ "@org_golang_x_sys//internal/unsafeheader:unsafeheader_test",
+ "@org_golang_x_sys//plan9:plan9_test",
+ "@org_golang_x_sys//unix/internal/mkmerge:mkmerge_test",
+ "@org_golang_x_sys//windows/registry:registry_test",
+ "@org_golang_x_sys//windows/svc:svc_test",
+ "@org_golang_x_sys//windows/svc/eventlog:eventlog_test",
+ "@org_golang_x_sys//windows/svc/mgr:mgr_test",
+ ],
+)
+
+test_suite(
+ name = "org_golang_x_text",
+ tests = [
+ "@org_golang_x_text//cases:cases_test",
+ "@org_golang_x_text//collate:collate_test",
+ "@org_golang_x_text//collate/build:build_test",
+ "@org_golang_x_text//currency:currency_test",
+ "@org_golang_x_text//date:date_test",
+ "@org_golang_x_text//encoding:encoding_test",
+ "@org_golang_x_text//encoding/htmlindex:htmlindex_test",
+ "@org_golang_x_text//encoding/ianaindex:ianaindex_test",
+ "@org_golang_x_text//feature/plural:plural_test",
+ "@org_golang_x_text//internal:internal_test",
+ "@org_golang_x_text//internal/catmsg:catmsg_test",
+ "@org_golang_x_text//internal/colltab:colltab_test",
+ "@org_golang_x_text//internal/export/idna:idna_test",
+ "@org_golang_x_text//internal/export/unicode:unicode_test",
+ "@org_golang_x_text//internal/format:format_test",
+ "@org_golang_x_text//internal/language:language_test",
+ "@org_golang_x_text//internal/language/compact:compact_test",
+ "@org_golang_x_text//internal/number:number_test",
+ "@org_golang_x_text//internal/stringset:stringset_test",
+ "@org_golang_x_text//internal/tag:tag_test",
+ "@org_golang_x_text//internal/triegen:triegen_test",
+ "@org_golang_x_text//internal/ucd:ucd_test",
+ "@org_golang_x_text//language:language_test",
+ "@org_golang_x_text//language/display:display_test",
+ "@org_golang_x_text//message:message_test",
+ "@org_golang_x_text//message/catalog:catalog_test",
+ "@org_golang_x_text//number:number_test",
+ "@org_golang_x_text//runes:runes_test",
+ "@org_golang_x_text//search:search_test",
+ "@org_golang_x_text//secure/bidirule:bidirule_test",
+ "@org_golang_x_text//secure/precis:precis_test",
+ "@org_golang_x_text//transform:transform_test",
+ "@org_golang_x_text//unicode/bidi:bidi_test",
+ "@org_golang_x_text//unicode/cldr:cldr_test",
+ "@org_golang_x_text//unicode/norm:norm_test",
+ "@org_golang_x_text//unicode/rangetable:rangetable_test",
+ "@org_golang_x_text//unicode/runenames:runenames_test",
+ "@org_golang_x_text//width:width_test",
+ ],
+)
+
+test_suite(
+ name = "org_golang_x_tools",
+ tests = [
+ "@org_golang_x_tools//benchmark/parse:parse_test",
+ "@org_golang_x_tools//cmd/benchcmp:benchcmp_test",
+ "@org_golang_x_tools//cmd/digraph:digraph_test",
+ "@org_golang_x_tools//cmd/getgo:getgo_test",
+ "@org_golang_x_tools//cmd/go-contrib-init:go-contrib-init_test",
+ "@org_golang_x_tools//cmd/splitdwarf/internal/macho:macho_test",
+ "@org_golang_x_tools//cover:cover_test",
+ "@org_golang_x_tools//go/analysis:analysis_test",
+ "@org_golang_x_tools//go/analysis/passes/internal/analysisutil:analysisutil_test",
+ "@org_golang_x_tools//go/ast/astutil:astutil_test",
+ "@org_golang_x_tools//go/callgraph/static:static_test",
+ "@org_golang_x_tools//go/callgraph/vta/internal/trie:trie_test",
+ "@org_golang_x_tools//go/cfg:cfg_test",
+ "@org_golang_x_tools//go/vcs:vcs_test",
+ "@org_golang_x_tools//godoc/redirect:redirect_test",
+ "@org_golang_x_tools//godoc/vfs:vfs_test",
+ "@org_golang_x_tools//godoc/vfs/gatefs:gatefs_test",
+ "@org_golang_x_tools//godoc/vfs/mapfs:mapfs_test",
+ "@org_golang_x_tools//internal/bug:bug_test",
+ "@org_golang_x_tools//internal/diff:diff_test",
+ "@org_golang_x_tools//internal/diff/lcs:lcs_test",
+ "@org_golang_x_tools//internal/diff/myers:myers_test",
+ "@org_golang_x_tools//internal/event:event_test",
+ "@org_golang_x_tools//internal/event/export:export_test",
+ "@org_golang_x_tools//internal/event/export/ocagent:ocagent_test",
+ "@org_golang_x_tools//internal/event/export/ocagent/wire:wire_test",
+ "@org_golang_x_tools//internal/event/label:label_test",
+ "@org_golang_x_tools//internal/fastwalk:fastwalk_test",
+ "@org_golang_x_tools//internal/fuzzy:fuzzy_test",
+ "@org_golang_x_tools//internal/gopathwalk:gopathwalk_test",
+ "@org_golang_x_tools//internal/jsonrpc2:jsonrpc2_test",
+ "@org_golang_x_tools//internal/jsonrpc2/servertest:servertest_test",
+ "@org_golang_x_tools//internal/jsonrpc2_v2:jsonrpc2_v2_test",
+ "@org_golang_x_tools//internal/memoize:memoize_test",
+ "@org_golang_x_tools//internal/persistent:persistent_test",
+ "@org_golang_x_tools//internal/proxydir:proxydir_test",
+ "@org_golang_x_tools//internal/robustio:robustio_test",
+ "@org_golang_x_tools//internal/stack:stack_test",
+ "@org_golang_x_tools//internal/typesinternal:typesinternal_test",
+ "@org_golang_x_tools//playground/socket:socket_test",
+ "@org_golang_x_tools//refactor/satisfy:satisfy_test",
+ "@org_golang_x_tools//txtar:txtar_test",
+ ],
+)
+
+test_suite(
+ name = "com_github_golang_glog",
+ tests = [
+ "@com_github_golang_glog//:glog_test",
+ ],
+)
+
+test_suite(
+ name = "org_golang_x_sync",
+ tests = [
+ "@org_golang_x_sync//errgroup:errgroup_test",
+ "@org_golang_x_sync//semaphore:semaphore_test",
+ "@org_golang_x_sync//singleflight:singleflight_test",
+ "@org_golang_x_sync//syncmap:syncmap_test",
+ ],
+)
+
+test_suite(
+ name = "org_golang_x_mod",
+ tests = [
+ "@org_golang_x_mod//modfile:modfile_test",
+ "@org_golang_x_mod//module:module_test",
+ "@org_golang_x_mod//semver:semver_test",
+ "@org_golang_x_mod//sumdb:sumdb_test",
+ "@org_golang_x_mod//sumdb/dirhash:dirhash_test",
+ "@org_golang_x_mod//sumdb/note:note_test",
+ "@org_golang_x_mod//sumdb/storage:storage_test",
+ ],
+)
+
+build_test(
+ name = "build_only",
+ targets = [
+ "@org_golang_x_crypto//ssh/agent:agent",
+ "@org_golang_x_crypto//ssh/test:test",
+ "@org_golang_x_crypto//ssh:ssh",
+ "@org_golang_x_net//bpf:bpf",
+ "@org_golang_x_net//html/charset:charset",
+ "@org_golang_x_net//http2:http2",
+ "@org_golang_x_net//icmp:icmp",
+ "@org_golang_x_net//nettest:nettest",
+ "@org_golang_x_net//lif:lif",
+ "@org_golang_x_net//route:route",
+ "@org_golang_x_sys//unix:unix",
+ "@org_golang_x_sys//windows:windows",
+ "@org_golang_x_text//encoding/charmap:charmap",
+ "@org_golang_x_text//encoding/japanese:japanese",
+ "@org_golang_x_text//encoding/korean:korean",
+ "@org_golang_x_text//encoding/simplifiedchinese:simplifiedchinese",
+ "@org_golang_x_text//encoding/traditionalchinese:traditionalchinese",
+ "@org_golang_x_text//encoding/unicode/utf32:utf32",
+ "@org_golang_x_text//encoding/unicode:unicode",
+ "@org_golang_x_text//message/pipeline:pipeline",
+ "@org_golang_x_tools//blog:blog",
+ "@org_golang_x_tools//cmd/bundle:bundle",
+ "@org_golang_x_tools//cmd/callgraph:callgraph",
+ "@org_golang_x_tools//cmd/file2fuzz:file2fuzz",
+ "@org_golang_x_tools//cmd/fiximports:fiximports",
+ "@org_golang_x_tools//cmd/godoc:godoc",
+ "@org_golang_x_tools//cmd/gorename:gorename",
+ "@org_golang_x_tools//cmd/guru:guru",
+ "@org_golang_x_tools//cmd/signature-fuzzer/fuzz-driver:fuzz-driver",
+ "@org_golang_x_tools//cmd/signature-fuzzer/fuzz-runner:fuzz-runner",
+ "@org_golang_x_tools//cmd/stringer:stringer",
+ "@org_golang_x_tools//container/intsets:intsets",
+ "@org_golang_x_tools//copyright:copyright",
+ "@org_golang_x_tools//go/analysis/analysistest:analysistest",
+ "@org_golang_x_tools//go/analysis/multichecker:multichecker",
+ "@org_golang_x_tools//go/analysis/passes/asmdecl:asmdecl",
+ "@org_golang_x_tools//go/analysis/passes/assign:assign",
+ "@org_golang_x_tools//go/analysis/passes/atomic:atomic",
+ "@org_golang_x_tools//go/analysis/passes/atomicalign:atomicalign",
+ "@org_golang_x_tools//go/analysis/passes/bools:bools",
+ "@org_golang_x_tools//go/analysis/passes/buildssa:buildssa",
+ "@org_golang_x_tools//go/analysis/passes/buildtag:buildtag",
+ "@org_golang_x_tools//go/analysis/passes/cgocall:cgocall",
+ "@org_golang_x_tools//go/analysis/passes/composite:composite",
+ "@org_golang_x_tools//go/analysis/passes/copylock:copylock",
+ "@org_golang_x_tools//go/analysis/passes/ctrlflow:ctrlflow",
+ "@org_golang_x_tools//go/analysis/passes/deepequalerrors:deepequalerrors",
+ "@org_golang_x_tools//go/analysis/passes/errorsas:errorsas",
+ "@org_golang_x_tools//go/analysis/passes/fieldalignment:fieldalignment",
+ "@org_golang_x_tools//go/analysis/passes/findcall:findcall",
+ "@org_golang_x_tools//go/analysis/passes/framepointer:framepointer",
+ "@org_golang_x_tools//go/analysis/passes/httpresponse:httpresponse",
+ "@org_golang_x_tools//go/analysis/passes/ifaceassert:ifaceassert",
+ "@org_golang_x_tools//go/analysis/passes/loopclosure:loopclosure",
+ "@org_golang_x_tools//go/analysis/passes/lostcancel:lostcancel",
+ "@org_golang_x_tools//go/analysis/passes/nilfunc:nilfunc",
+ "@org_golang_x_tools//go/analysis/passes/nilness:nilness",
+ "@org_golang_x_tools//go/analysis/passes/pkgfact:pkgfact",
+ "@org_golang_x_tools//go/analysis/passes/printf:printf",
+ "@org_golang_x_tools//go/analysis/passes/reflectvaluecompare:reflectvaluecompare",
+ "@org_golang_x_tools//go/analysis/passes/shadow:shadow",
+ "@org_golang_x_tools//go/analysis/passes/shift:shift",
+ "@org_golang_x_tools//go/analysis/passes/sigchanyzer:sigchanyzer",
+ "@org_golang_x_tools//go/analysis/passes/sortslice:sortslice",
+ "@org_golang_x_tools//go/analysis/passes/stdmethods:stdmethods",
+ "@org_golang_x_tools//go/analysis/passes/stringintconv:stringintconv",
+ "@org_golang_x_tools//go/analysis/passes/structtag:structtag",
+ "@org_golang_x_tools//go/analysis/passes/testinggoroutine:testinggoroutine",
+ "@org_golang_x_tools//go/analysis/passes/tests:tests",
+ "@org_golang_x_tools//go/analysis/passes/unmarshal:unmarshal",
+ "@org_golang_x_tools//go/analysis/passes/unreachable:unreachable",
+ "@org_golang_x_tools//go/analysis/passes/unsafeptr:unsafeptr",
+ "@org_golang_x_tools//go/analysis/passes/unusedresult:unusedresult",
+ "@org_golang_x_tools//go/analysis/passes/unusedwrite:unusedwrite",
+ "@org_golang_x_tools//go/analysis/passes/timeformat:timeformat",
+ "@org_golang_x_tools//go/analysis/passes/usesgenerics:usesgenerics",
+ "@org_golang_x_tools//go/analysis/unitchecker:unitchecker",
+ "@org_golang_x_tools//go/ast/inspector:inspector",
+ "@org_golang_x_tools//go/buildutil:buildutil",
+ "@org_golang_x_tools//go/callgraph/cha:cha",
+ "@org_golang_x_tools//go/callgraph/rta:rta",
+ "@org_golang_x_tools//go/callgraph/vta:vta",
+ "@org_golang_x_tools//go/expect:expect",
+ "@org_golang_x_tools//go/gccgoexportdata:gccgoexportdata",
+ "@org_golang_x_tools//go/gcexportdata:gcexportdata",
+ "@org_golang_x_tools//go/loader:loader",
+ "@org_golang_x_tools//go/packages/packagestest/testdata:testdata",
+ "@org_golang_x_tools//go/packages/packagestest:packagestest",
+ "@org_golang_x_tools//go/packages:packages",
+ "@org_golang_x_tools//go/pointer:pointer",
+ "@org_golang_x_tools//go/ssa/interp:interp",
+ "@org_golang_x_tools//go/ssa/ssautil:ssautil",
+ "@org_golang_x_tools//go/ssa:ssa",
+ "@org_golang_x_tools//go/types/typeutil:typeutil",
+ "@org_golang_x_tools//go/types/objectpath:objectpath",
+ "@org_golang_x_tools//godoc/static:static",
+ "@org_golang_x_tools//godoc/vfs/zipfs:zipfs",
+ "@org_golang_x_tools//godoc:godoc",
+ "@org_golang_x_tools//present:present",
+ "@org_golang_x_tools//refactor/eg:eg",
+ "@org_golang_x_tools//refactor/importgraph:importgraph",
+ "@org_golang_x_tools//refactor/rename:rename",
+ "@org_golang_x_mod//sumdb/tlog:tlog",
+ "@org_golang_x_mod//zip:zip",
+ ],
+)
diff --git a/tests/integration/popular_repos/README.rst b/tests/integration/popular_repos/README.rst
new file mode 100644
index 00000000..ad071a37
--- /dev/null
+++ b/tests/integration/popular_repos/README.rst
@@ -0,0 +1,234 @@
+Popular repository tests
+========================
+
+These tests are designed to check that gazelle and rules_go together can cope
+with a list of popluar repositories people depend on.
+
+It helps catch changes that might break a large number of users.
+
+.. contents::
+
+org_golang_x_crypto
+___________________
+
+This runs tests from the repository `golang.org/x/crypto <https://golang.org/x/crypto>`_
+
+* @org_golang_x_crypto//acme:acme_test
+* @org_golang_x_crypto//acme/autocert:autocert_test
+* @org_golang_x_crypto//argon2:argon2_test
+* @org_golang_x_crypto//bcrypt:bcrypt_test
+* @org_golang_x_crypto//blake2b:blake2b_test
+* @org_golang_x_crypto//blake2s:blake2s_test
+* @org_golang_x_crypto//blowfish:blowfish_test
+* @org_golang_x_crypto//bn256:bn256_test
+* @org_golang_x_crypto//cast5:cast5_test
+* @org_golang_x_crypto//chacha20:chacha20_test
+* @org_golang_x_crypto//chacha20poly1305:chacha20poly1305_test
+* @org_golang_x_crypto//cryptobyte:cryptobyte_test
+* @org_golang_x_crypto//curve25519:curve25519_test
+* @org_golang_x_crypto//ed25519:ed25519_test
+* @org_golang_x_crypto//hkdf:hkdf_test
+* @org_golang_x_crypto//internal/subtle:subtle_test
+* @org_golang_x_crypto//md4:md4_test
+* @org_golang_x_crypto//nacl/auth:auth_test
+* @org_golang_x_crypto//nacl/box:box_test
+* @org_golang_x_crypto//nacl/secretbox:secretbox_test
+* @org_golang_x_crypto//nacl/sign:sign_test
+* @org_golang_x_crypto//ocsp:ocsp_test
+* @org_golang_x_crypto//openpgp:openpgp_test
+* @org_golang_x_crypto//openpgp/armor:armor_test
+* @org_golang_x_crypto//openpgp/clearsign:clearsign_test
+* @org_golang_x_crypto//openpgp/elgamal:elgamal_test
+* @org_golang_x_crypto//openpgp/packet:packet_test
+* @org_golang_x_crypto//openpgp/s2k:s2k_test
+* @org_golang_x_crypto//otr:otr_test
+* @org_golang_x_crypto//pbkdf2:pbkdf2_test
+* @org_golang_x_crypto//pkcs12:pkcs12_test
+* @org_golang_x_crypto//pkcs12/internal/rc2:rc2_test
+* @org_golang_x_crypto//poly1305:poly1305_test
+* @org_golang_x_crypto//ripemd160:ripemd160_test
+* @org_golang_x_crypto//salsa20:salsa20_test
+* @org_golang_x_crypto//salsa20/salsa:salsa_test
+* @org_golang_x_crypto//scrypt:scrypt_test
+* @org_golang_x_crypto//sha3:sha3_test
+* @org_golang_x_crypto//ssh/internal/bcrypt_pbkdf:bcrypt_pbkdf_test
+* @org_golang_x_crypto//ssh/knownhosts:knownhosts_test
+* @org_golang_x_crypto//tea:tea_test
+* @org_golang_x_crypto//twofish:twofish_test
+* @org_golang_x_crypto//xtea:xtea_test
+* @org_golang_x_crypto//xts:xts_test
+
+
+org_golang_x_net
+________________
+
+This runs tests from the repository `golang.org/x/net <https://golang.org/x/net>`_
+
+* @org_golang_x_net//context:context_test
+* @org_golang_x_net//context/ctxhttp:ctxhttp_test
+* @org_golang_x_net//dns/dnsmessage:dnsmessage_test
+* @org_golang_x_net//html:html_test
+* @org_golang_x_net//html/atom:atom_test
+* @org_golang_x_net//http/httpguts:httpguts_test
+* @org_golang_x_net//http/httpproxy:httpproxy_test
+* @org_golang_x_net//http2/h2c:h2c_test
+* @org_golang_x_net//http2/hpack:hpack_test
+* @org_golang_x_net//idna:idna_test
+* @org_golang_x_net//internal/socks:socks_test
+* @org_golang_x_net//internal/sockstest:sockstest_test
+* @org_golang_x_net//internal/timeseries:timeseries_test
+* @org_golang_x_net//ipv4:ipv4_test
+* @org_golang_x_net//ipv6:ipv6_test
+* @org_golang_x_net//netutil:netutil_test
+* @org_golang_x_net//proxy:proxy_test
+* @org_golang_x_net//publicsuffix:publicsuffix_test
+* @org_golang_x_net//trace:trace_test
+* @org_golang_x_net//webdav:webdav_test
+* @org_golang_x_net//webdav/internal/xml:xml_test
+* @org_golang_x_net//websocket:websocket_test
+* @org_golang_x_net//xsrftoken:xsrftoken_test
+
+
+org_golang_x_sys
+________________
+
+This runs tests from the repository `golang.org/x/sys <https://golang.org/x/sys>`_
+
+* @org_golang_x_sys//cpu:cpu_test
+* @org_golang_x_sys//execabs:execabs_test
+* @org_golang_x_sys//internal/unsafeheader:unsafeheader_test
+* @org_golang_x_sys//plan9:plan9_test
+* @org_golang_x_sys//unix/internal/mkmerge:mkmerge_test
+* @org_golang_x_sys//windows/registry:registry_test
+* @org_golang_x_sys//windows/svc:svc_test
+* @org_golang_x_sys//windows/svc/eventlog:eventlog_test
+* @org_golang_x_sys//windows/svc/mgr:mgr_test
+
+
+org_golang_x_text
+_________________
+
+This runs tests from the repository `golang.org/x/text <https://golang.org/x/text>`_
+
+* @org_golang_x_text//cases:cases_test
+* @org_golang_x_text//collate:collate_test
+* @org_golang_x_text//collate/build:build_test
+* @org_golang_x_text//currency:currency_test
+* @org_golang_x_text//date:date_test
+* @org_golang_x_text//encoding:encoding_test
+* @org_golang_x_text//encoding/htmlindex:htmlindex_test
+* @org_golang_x_text//encoding/ianaindex:ianaindex_test
+* @org_golang_x_text//feature/plural:plural_test
+* @org_golang_x_text//internal:internal_test
+* @org_golang_x_text//internal/catmsg:catmsg_test
+* @org_golang_x_text//internal/colltab:colltab_test
+* @org_golang_x_text//internal/export/idna:idna_test
+* @org_golang_x_text//internal/export/unicode:unicode_test
+* @org_golang_x_text//internal/format:format_test
+* @org_golang_x_text//internal/language:language_test
+* @org_golang_x_text//internal/language/compact:compact_test
+* @org_golang_x_text//internal/number:number_test
+* @org_golang_x_text//internal/stringset:stringset_test
+* @org_golang_x_text//internal/tag:tag_test
+* @org_golang_x_text//internal/triegen:triegen_test
+* @org_golang_x_text//internal/ucd:ucd_test
+* @org_golang_x_text//language:language_test
+* @org_golang_x_text//language/display:display_test
+* @org_golang_x_text//message:message_test
+* @org_golang_x_text//message/catalog:catalog_test
+* @org_golang_x_text//number:number_test
+* @org_golang_x_text//runes:runes_test
+* @org_golang_x_text//search:search_test
+* @org_golang_x_text//secure/bidirule:bidirule_test
+* @org_golang_x_text//secure/precis:precis_test
+* @org_golang_x_text//transform:transform_test
+* @org_golang_x_text//unicode/bidi:bidi_test
+* @org_golang_x_text//unicode/cldr:cldr_test
+* @org_golang_x_text//unicode/norm:norm_test
+* @org_golang_x_text//unicode/rangetable:rangetable_test
+* @org_golang_x_text//unicode/runenames:runenames_test
+* @org_golang_x_text//width:width_test
+
+
+org_golang_x_tools
+__________________
+
+This runs tests from the repository `golang.org/x/tools <https://golang.org/x/tools>`_
+
+* @org_golang_x_tools//benchmark/parse:parse_test
+* @org_golang_x_tools//cmd/benchcmp:benchcmp_test
+* @org_golang_x_tools//cmd/digraph:digraph_test
+* @org_golang_x_tools//cmd/getgo:getgo_test
+* @org_golang_x_tools//cmd/go-contrib-init:go-contrib-init_test
+* @org_golang_x_tools//cmd/splitdwarf/internal/macho:macho_test
+* @org_golang_x_tools//cover:cover_test
+* @org_golang_x_tools//go/analysis:analysis_test
+* @org_golang_x_tools//go/analysis/passes/internal/analysisutil:analysisutil_test
+* @org_golang_x_tools//go/ast/astutil:astutil_test
+* @org_golang_x_tools//go/callgraph/static:static_test
+* @org_golang_x_tools//go/callgraph/vta/internal/trie:trie_test
+* @org_golang_x_tools//go/cfg:cfg_test
+* @org_golang_x_tools//go/vcs:vcs_test
+* @org_golang_x_tools//godoc/redirect:redirect_test
+* @org_golang_x_tools//godoc/vfs:vfs_test
+* @org_golang_x_tools//godoc/vfs/gatefs:gatefs_test
+* @org_golang_x_tools//godoc/vfs/mapfs:mapfs_test
+* @org_golang_x_tools//internal/bug:bug_test
+* @org_golang_x_tools//internal/diff:diff_test
+* @org_golang_x_tools//internal/diff/lcs:lcs_test
+* @org_golang_x_tools//internal/diff/myers:myers_test
+* @org_golang_x_tools//internal/event:event_test
+* @org_golang_x_tools//internal/event/export:export_test
+* @org_golang_x_tools//internal/event/export/ocagent:ocagent_test
+* @org_golang_x_tools//internal/event/export/ocagent/wire:wire_test
+* @org_golang_x_tools//internal/event/label:label_test
+* @org_golang_x_tools//internal/fastwalk:fastwalk_test
+* @org_golang_x_tools//internal/fuzzy:fuzzy_test
+* @org_golang_x_tools//internal/gopathwalk:gopathwalk_test
+* @org_golang_x_tools//internal/jsonrpc2:jsonrpc2_test
+* @org_golang_x_tools//internal/jsonrpc2/servertest:servertest_test
+* @org_golang_x_tools//internal/jsonrpc2_v2:jsonrpc2_v2_test
+* @org_golang_x_tools//internal/memoize:memoize_test
+* @org_golang_x_tools//internal/persistent:persistent_test
+* @org_golang_x_tools//internal/proxydir:proxydir_test
+* @org_golang_x_tools//internal/robustio:robustio_test
+* @org_golang_x_tools//internal/stack:stack_test
+* @org_golang_x_tools//internal/typesinternal:typesinternal_test
+* @org_golang_x_tools//playground/socket:socket_test
+* @org_golang_x_tools//refactor/satisfy:satisfy_test
+* @org_golang_x_tools//txtar:txtar_test
+
+
+com_github_golang_glog
+______________________
+
+This runs tests from the repository `github.com/golang/glog <https://github.com/golang/glog>`_
+
+* @com_github_golang_glog//:glog_test
+
+
+org_golang_x_sync
+_________________
+
+This runs tests from the repository `golang.org/x/sync <https://golang.org/x/sync>`_
+
+* @org_golang_x_sync//errgroup:errgroup_test
+* @org_golang_x_sync//semaphore:semaphore_test
+* @org_golang_x_sync//singleflight:singleflight_test
+* @org_golang_x_sync//syncmap:syncmap_test
+
+
+org_golang_x_mod
+________________
+
+This runs tests from the repository `golang.org/x/mod <https://golang.org/x/mod>`_
+
+* @org_golang_x_mod//modfile:modfile_test
+* @org_golang_x_mod//module:module_test
+* @org_golang_x_mod//semver:semver_test
+* @org_golang_x_mod//sumdb:sumdb_test
+* @org_golang_x_mod//sumdb/dirhash:dirhash_test
+* @org_golang_x_mod//sumdb/note:note_test
+* @org_golang_x_mod//sumdb/storage:storage_test
+
+
diff --git a/tests/integration/popular_repos/popular_repos.bzl b/tests/integration/popular_repos/popular_repos.bzl
new file mode 100644
index 00000000..752b654d
--- /dev/null
+++ b/tests/integration/popular_repos/popular_repos.bzl
@@ -0,0 +1,75 @@
+# Copyright 2017 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.
+
+##############################
+# Generated file, do not edit!
+##############################
+
+load("@bazel_gazelle//:def.bzl", "go_repository")
+
+def _maybe(repo_rule, name, **kwargs):
+ if name not in native.existing_rules():
+ repo_rule(name = name, **kwargs)
+
+def popular_repos():
+ _maybe(
+ go_repository,
+ name = "org_golang_x_crypto",
+ importpath = "golang.org/x/crypto",
+ strip_prefix = "crypto-5ea612d1eb830b38bc4e914e37f55311eb58adce",
+ type = "zip",
+ urls = ["https://codeload.github.com/golang/crypto/zip/5ea612d1eb830b38bc4e914e37f55311eb58adce"],
+ )
+ _maybe(
+ go_repository,
+ name = "org_golang_x_net",
+ importpath = "golang.org/x/net",
+ commit = "e18ecbb051101a46fc263334b127c89bc7bff7ea",
+ )
+ _maybe(
+ go_repository,
+ name = "org_golang_x_sys",
+ importpath = "golang.org/x/sys",
+ commit = "390168757d9c647283340d526204e3409d5903f3",
+ )
+ _maybe(
+ go_repository,
+ name = "org_golang_x_text",
+ importpath = "golang.org/x/text",
+ commit = "e3aa4adf54f644ca0cb35f1f1fb19b239c40ef04",
+ )
+ _maybe(
+ go_repository,
+ name = "org_golang_x_tools",
+ importpath = "golang.org/x/tools",
+ commit = "fe37c9e135b934191089b245ac29325091462508",
+ )
+ _maybe(
+ go_repository,
+ name = "com_github_golang_glog",
+ importpath = "github.com/golang/glog",
+ commit = "23def4e6c14b4da8ac2ed8007337bc5eb5007998",
+ )
+ _maybe(
+ go_repository,
+ name = "org_golang_x_sync",
+ importpath = "golang.org/x/sync",
+ commit = "036812b2e83c0ddf193dd5a34e034151da389d09",
+ )
+ _maybe(
+ go_repository,
+ name = "org_golang_x_mod",
+ importpath = "golang.org/x/mod",
+ commit = "86c51ed26bb44749b7d60a57bab0e7524656fe8a",
+ )
diff --git a/tests/integration/popular_repos/popular_repos.py b/tests/integration/popular_repos/popular_repos.py
new file mode 100755
index 00000000..dbe645bf
--- /dev/null
+++ b/tests/integration/popular_repos/popular_repos.py
@@ -0,0 +1,336 @@
+#!/usr/bin/env python3
+# Copyright 2017 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.
+
+from subprocess import check_output, call
+from sys import exit
+from os import path
+
+POPULAR_REPOS = [
+ dict(
+ name = "org_golang_x_crypto",
+ importpath = "golang.org/x/crypto",
+ urls = "https://codeload.github.com/golang/crypto/zip/5ea612d1eb830b38bc4e914e37f55311eb58adce",
+ strip_prefix = "crypto-5ea612d1eb830b38bc4e914e37f55311eb58adce",
+ type = "zip",
+ excludes = [
+ "internal/wycheproof:wycheproof_test", # Needs GOROOT
+ "ssh/agent:agent_test",
+ "ssh/test:test_test",
+ "ssh:ssh_test",
+ ],
+ ),
+
+ dict(
+ name = "org_golang_x_net",
+ importpath = "golang.org/x/net",
+ commit = "e18ecbb051101a46fc263334b127c89bc7bff7ea",
+ excludes = [
+ "bpf:bpf_test", # Needs testdata directory
+ "html/charset:charset_test", # Needs testdata directory
+ "http2:http2_test", # Needs testdata directory
+ "icmp:icmp_test", # icmp requires adjusting kernel options.
+ "internal/socket:socket_test", # Needs GOROOT.
+ "nettest:nettest_test", #
+ "lif:lif_test",
+ ],
+ darwin_tests = [
+ "route:route_test", # Not supported on linux
+ ]
+ ),
+
+ dict(
+ name = "org_golang_x_sys",
+ importpath = "golang.org/x/sys",
+ commit = "390168757d9c647283340d526204e3409d5903f3",
+ excludes = [
+ "unix:unix_test", # TestOpenByHandleAt reads source file.
+ "windows:windows_test", # Needs testdata directory
+ ],
+ ),
+
+ dict(
+ name = "org_golang_x_text",
+ importpath = "golang.org/x/text",
+ commit = "e3aa4adf54f644ca0cb35f1f1fb19b239c40ef04",
+ excludes = [
+ "encoding/charmap:charmap_test", # Needs testdata directory
+ "encoding/japanese:japanese_test", # Needs testdata directory
+ "encoding/korean:korean_test", # Needs testdata directory
+ "encoding/simplifiedchinese:simplifiedchinese_test", # Needs testdata directory
+ "encoding/traditionalchinese:traditionalchinese_test", # Needs testdata directory
+ "encoding/unicode/utf32:utf32_test", # Needs testdata directory
+ "encoding/unicode:unicode_test", # Needs testdata directory
+ "internal/cldrtree:cldrtree_test", # Needs testdata directory
+ "internal/gen/bitfield:bitfield_test", # Needs runfiles
+ "message/pipeline/testdata/test1:test1_test", # Not a real test
+ "message/pipeline:pipeline_test", # Needs testdata directory
+ ],
+ ),
+
+ dict(
+ name = "org_golang_x_tools",
+ importpath = "golang.org/x/tools",
+ commit = "fe37c9e135b934191089b245ac29325091462508",
+ excludes = [
+ "blog:blog_test", # Needs goldmark
+ "cmd/bundle:bundle_test", # Needs testdata directory
+ "cmd/callgraph/testdata/src/pkg:pkg_test", # is testdata
+ "cmd/callgraph:callgraph_test", # Needs testdata directory
+ "cmd/cover:cover_test", # Needs testdata directory
+ "cmd/file2fuzz:file2fuzz_test", # Requires working GOROOT, uses go build
+ "cmd/fiximports:fiximports_test", # requires working GOROOT, not present in CI.
+ "cmd/godoc:godoc_test", # TODO(#417)
+ "cmd/gorename:gorename_test", # TODO(#417)
+ "cmd/guru/testdata/src/referrers:referrers_test", # Not a real test
+ "cmd/guru:guru_test", # Needs testdata directory
+ "cmd/signature-fuzzer/fuzz-driver:fuzz-driver_test", # requires working GOROOT
+ "cmd/signature-fuzzer/fuzz-runner:fuzz-runner_test", # requires working GOROOT
+ "cmd/signature-fuzzer/internal/fuzz-generator:fuzz-generator_test", # requires working GOROOT
+ "cmd/stringer:stringer_test", # Needs testdata directory
+ "container/intsets:intsets_test", # TODO(#413): External test depends on symbols defined in internal test.
+ "copyright:copyright_test", # # requires runfiles
+ "go/analysis/analysistest:analysistest_test", # requires build cache
+ "go/analysis/internal/analysisflags:analysisflags_test", # calls os.Exit(0) in a test
+ "go/analysis/internal/checker:checker_test", # loads test package with go/packages, which probably needs go list
+ "go/analysis/multichecker:multichecker_test", # requires go vet
+ "go/analysis/passes/asmdecl:asmdecl_test", # Needs testdata directory
+ "go/analysis/passes/assign:assign_test", # Needs testdata directory
+ "go/analysis/passes/atomic:atomic_test", # Needs testdata directory
+ "go/analysis/passes/atomicalign:atomicalign_test", # requires go list
+ "go/analysis/passes/bools:bools_test", # Needs testdata directory
+ "go/analysis/passes/buildssa:buildssa_test", # Needs testdata directory
+ "go/analysis/passes/buildtag:buildtag_test", # Needs testdata directory
+ "go/analysis/passes/cgocall:cgocall_test", # Needs testdata directory
+ "go/analysis/passes/composite:composite_test", # Needs testdata directory
+ "go/analysis/passes/composite/testdata/src/a:a_test", # Does not compile
+ "go/analysis/passes/copylock:copylock_test", # Needs testdata directory
+ "go/analysis/passes/ctrlflow:ctrlflow_test", # Needs testdata directory
+ "go/analysis/passes/deepequalerrors:deepequalerrors_test", # requires go list
+ "go/analysis/passes/errorsas:errorsas_test", # requires go list and testdata
+ "go/analysis/passes/fieldalignment:fieldalignment_test", # Needs GOROOT
+ "go/analysis/passes/findcall:findcall_test", # requires build cache
+ "go/analysis/passes/framepointer:framepointer_test", # Needs GOROOT
+ "go/analysis/passes/httpresponse:httpresponse_test", # Needs testdata directory
+ "go/analysis/passes/ifaceassert:ifaceassert_test", # Needs GOROOT
+ "go/analysis/passes/loopclosure:loopclosure_test", # Needs testdata directory
+ "go/analysis/passes/lostcancel:lostcancel_test", # Needs testdata directory
+ "go/analysis/passes/nilfunc:nilfunc_test", # Needs testdata directory
+ "go/analysis/passes/nilness:nilness_test", # Needs testdata directory
+ "go/analysis/passes/pkgfact:pkgfact_test", # requires go list
+ "go/analysis/passes/printf:printf_test", # Needs testdata directory
+ "go/analysis/passes/reflectvaluecompare:reflectvaluecompare_test", # Needs testdata directory
+ "go/analysis/passes/shadow:shadow_test", # Needs testdata directory
+ "go/analysis/passes/shift:shift_test", # Needs testdata director
+ "go/analysis/passes/sigchanyzer:sigchanyzer_test", # Needs testdata directory
+ "go/analysis/passes/sortslice:sortslice_test", # Needs 'go list'
+ "go/analysis/passes/stdmethods:stdmethods_test", # Needs testdata directory
+ "go/analysis/passes/stringintconv:stringintconv_test", # Needs 'go list'
+ "go/analysis/passes/structtag:structtag_test", # Needs testdata directory
+ "go/analysis/passes/testinggoroutine:testinggoroutine_test", # Need 'go env'
+ "go/analysis/passes/tests/testdata/src/a:a_test", # Not a real test
+ "go/analysis/passes/tests/testdata/src/b_x_test:b_x_test_test", # Not a real test
+ "go/analysis/passes/tests/testdata/src/divergent:divergent_test", # Not a real test
+ "go/analysis/passes/tests/testdata/src/typeparams:typeparams_test", # Not a real test
+ "go/analysis/passes/tests:tests_test", # Needs testdata directory
+ "go/analysis/passes/unmarshal:unmarshal_test", # Needs go list
+ "go/analysis/passes/unreachable:unreachable_test", # Needs testdata directory
+ "go/analysis/passes/unsafeptr:unsafeptr_test", # Needs testdata directory
+ "go/analysis/passes/unusedresult:unusedresult_test", # Needs testdata directory
+ "go/analysis/passes/unusedwrite:unusedwrite_test", # Needs testdata directory
+ "go/analysis/passes/timeformat:timeformat_test", # Needs go tool
+ "go/analysis/passes/usesgenerics:usesgenerics_test", # Needs go tool
+ "go/analysis/unitchecker:unitchecker_test", # requires go vet
+ "go/ast/inspector:inspector_test", # requires GOROOT and GOPATH
+ "go/buildutil:buildutil_test", # Needs testdata directory
+ "go/callgraph/cha:cha_test", # Needs testdata directory
+ "go/callgraph/rta:rta_test", # Needs testdata directory
+ "go/callgraph/vta:vta_test", # Needs testdata directory
+ "go/expect:expect_test", # Needs testdata directory
+ "go/gccgoexportdata:gccgoexportdata_test", # Needs testdata directory
+ "go/gcexportdata:gcexportdata_test", # Needs testdata directory
+ "go/internal/gccgoimporter:gccgoimporter_test", # Needs testdata directory
+ "go/loader:loader_test", # Needs testdata directory
+ "go/packages/packagestest/testdata/groups/two/primarymod/expect:expect_test", # Is testdata
+ "go/packages/packagestest/testdata:testdata_test", # Is testdata
+ "go/packages/packagestest:packagestest_test", # requires build cache
+ "go/packages:packages_test", # Hah!
+ "go/pointer:pointer_test", # Needs testdata directory
+ "go/ssa/interp:interp_test", # Needs testdata directory
+ "go/ssa/ssautil:ssautil_test", # Needs testdata directory
+ "go/ssa:ssa_test", # Needs testdata directory
+ "go/types/typeutil:typeutil_test", # requires GOROOT
+ "go/types/objectpath:objectpath_test", # Incomaptible with Go SDK 1.18.3. Fixed in master but not yet released. TODO: fixme
+ "godoc/static:static_test", # requires data files
+ "godoc/vfs/zipfs:zipfs_test", # requires GOROOT
+ "godoc:godoc_test", # requires GOROOT and GOPATH
+ "internal/apidiff:apidiff_test", # Needs testdata directory
+ "internal/diff/difftest:difftest_test", # Needs diff tool
+ "internal/facts:facts_test", # loads test package with go/packages, which probably needs go list
+ "internal/gcimporter:gcimporter_test", # Needs testdata directory
+ "internal/gocommand:gocommand_test", # Needs go tool
+ "internal/imports:imports_test", # Needs testdata directory
+ "internal/typeparams:typeparams_test", # Needs go tool
+ "present:present_test", # Needs goldmark
+ "refactor/eg:eg_test", # Needs testdata directory
+ "refactor/importgraph:importgraph_test", # TODO(#417)
+ "refactor/rename:rename_test", # TODO(#417)
+ ],
+ ),
+
+ dict(
+ name = "com_github_golang_glog",
+ importpath = "github.com/golang/glog",
+ commit = "23def4e6c14b4da8ac2ed8007337bc5eb5007998",
+ ),
+
+ dict(
+ name = "org_golang_x_sync",
+ importpath = "golang.org/x/sync",
+ commit = "036812b2e83c0ddf193dd5a34e034151da389d09",
+ ),
+
+ dict(
+ name = "org_golang_x_mod",
+ importpath = "golang.org/x/mod",
+ commit = "86c51ed26bb44749b7d60a57bab0e7524656fe8a",
+ excludes = [
+ "sumdb/tlog:tlog_test", # Needs network, not available on RBE
+ "zip:zip_test", # Needs vcs tools, not available on RBE
+ ],
+ ),
+ ]
+
+COPYRIGHT_HEADER = """
+# Copyright 2017 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.
+
+##############################
+# Generated file, do not edit!
+##############################
+""".strip()
+
+BZL_HEADER = COPYRIGHT_HEADER + """
+
+load("@bazel_gazelle//:def.bzl", "go_repository")
+
+def _maybe(repo_rule, name, **kwargs):
+ if name not in native.existing_rules():
+ repo_rule(name = name, **kwargs)
+
+def popular_repos():
+"""
+
+BUILD_HEADER = COPYRIGHT_HEADER
+
+DOCUMENTATION_HEADER = """
+Popular repository tests
+========================
+
+These tests are designed to check that gazelle and rules_go together can cope
+with a list of popluar repositories people depend on.
+
+It helps catch changes that might break a large number of users.
+
+.. contents::
+
+""".lstrip()
+
+LOAD_BAZEL_TEST_RULE = """
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
+"""
+
+def popular_repos_bzl():
+ with open(path.join(path.dirname(__file__), "popular_repos.bzl"), "w") as f:
+ f.write(BZL_HEADER)
+ for repo in POPULAR_REPOS:
+ f.write(" _maybe(\n go_repository,\n")
+ for k in ["name", "importpath", "commit", "strip_prefix", "type", "build_file_proto_mode"]:
+ if k in repo: f.write(' {} = "{}",\n'.format(k, repo[k]))
+ for k in ["urls"]:
+ if k in repo: f.write(' {} = ["{}"],\n'.format(k, repo[k]))
+ f.write(" )\n")
+
+def build_bazel():
+ with open(path.join(path.dirname(__file__), "BUILD.bazel"), "w") as f:
+ f.write(BUILD_HEADER)
+ f.write("\n" + LOAD_BAZEL_TEST_RULE)
+ build_only = []
+ for repo in POPULAR_REPOS:
+ name = repo["name"]
+ tests = check_output(["bazel", "query", "kind(go_test, \"@{}//...\")".format(name)], text=True).split("\n")
+ excludes = ["@{}//{}".format(name, l) for l in repo.get("excludes", [])]
+ for k in repo:
+ if k.endswith("_excludes") or k.endswith("_tests"):
+ excludes.extend(["@{}//{}".format(name, l) for l in repo[k]])
+ invalid_excludes = [t for t in excludes if not t in tests]
+ if invalid_excludes:
+ exit("Invalid excludes found: {}".format(invalid_excludes))
+ build_only.extend(excludes)
+ f.write('\ntest_suite(\n')
+ f.write(' name = "{}",\n'.format(name))
+ f.write(' tests = [\n')
+ actual = []
+ for test in sorted(tests, key=lambda test: test.replace(":", "!")):
+ if test in excludes or not test: continue
+ f.write(' "{}",\n'.format(test))
+ actual.append(test)
+ f.write(' ],\n')
+ #TODO: add in the platform "select" tests
+ f.write(')\n')
+ repo["actual"] = actual
+
+ # add bazel test rule
+ f.write('\nbuild_test(\n')
+ f.write(' name = "{}",\n'.format("build_only"))
+ f.write(' targets = [\n')
+ for package in build_only:
+ if "/internal/" not in package and "/testdata/" not in package:
+ if package.endswith("_test"):
+ f.write(' "{}",\n'.format(package[:-5]))
+ else:
+ f.write(' "{}",\n'.format(package))
+ f.write(' ],\n')
+ f.write(')\n')
+
+def readme_rst():
+ with open(path.join(path.dirname(__file__), "README.rst"), "w") as f:
+ f.write(DOCUMENTATION_HEADER)
+ for repo in POPULAR_REPOS:
+ name = repo["name"]
+ f.write("{}\n{}\n\n".format(name, "_"*len(name)))
+ f.write("This runs tests from the repository `{0} <https://{0}>`_\n\n".format(repo["importpath"]))
+ for test in repo["actual"]:
+ f.write("* {}\n".format(test))
+ f.write("\n\n")
+
+
+def main():
+ popular_repos_bzl()
+ build_bazel()
+ readme_rst()
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/integration/reproducibility/BUILD.bazel b/tests/integration/reproducibility/BUILD.bazel
new file mode 100644
index 00000000..db5fd9b6
--- /dev/null
+++ b/tests/integration/reproducibility/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "reproducibility_test",
+ srcs = ["reproducibility_test.go"],
+)
diff --git a/tests/integration/reproducibility/README.rst b/tests/integration/reproducibility/README.rst
new file mode 100644
index 00000000..1ac77510
--- /dev/null
+++ b/tests/integration/reproducibility/README.rst
@@ -0,0 +1,14 @@
+Reproducibility
+
+reproducibility_test
+--------------------
+Verifies that the files generated when building a set of targets are identical,
+even when built from multiple copies of the same workspace.
+
+Currently covers pure ``go_binary`` targets and a cgo ``go_binary`` with
+``linkmode = "c-archive"``.
+
+TODO: cover more modes. Currently, it seems like a cgo ``go_binary`` that
+produces an executable is not reproducible on macOS. This is most likely
+due to the external linker, since all the inputs to the linker are identical.
+Needs investigation.
diff --git a/tests/integration/reproducibility/reproducibility_test.go b/tests/integration/reproducibility/reproducibility_test.go
new file mode 100644
index 00000000..2e9bc591
--- /dev/null
+++ b/tests/integration/reproducibility/reproducibility_test.go
@@ -0,0 +1,384 @@
+// 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 reproducibility_test
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+ "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_library(
+ name = "empty_lib",
+ srcs = [],
+ importpath = "empty_lib",
+)
+
+go_binary(
+ name = "hello",
+ srcs = ["hello.go"],
+)
+
+go_binary(
+ name = "adder",
+ srcs = [
+ "adder_main.go",
+ "adder.go",
+ "add.c",
+ "add.cpp",
+ "add.h",
+ ],
+ cgo = True,
+ linkmode = "c-archive",
+)
+
+-- hello.go --
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("hello")
+}
+
+-- add.h --
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int add_c(int a, int b);
+int add_cpp(int a, int b);
+
+#ifdef __cplusplus
+}
+#endif
+
+-- add.c --
+#include "add.h"
+#include "_cgo_export.h"
+
+int add_c(int a, int b) { return add(a, b); }
+
+-- add.cpp --
+#include "add.h"
+#include "_cgo_export.h"
+
+int add_cpp(int a, int b) { return add(a, b); }
+
+-- adder.go --
+package main
+
+/*
+#include "add.h"
+*/
+import "C"
+
+func AddC(a, b int32) int32 {
+ return int32(C.add_c(C.int(a), C.int(b)))
+}
+
+func AddCPP(a, b int32) int32 {
+ return int32(C.add_cpp(C.int(a), C.int(b)))
+}
+
+//export add
+func add(a, b int32) int32 {
+ return a + b
+}
+
+-- adder_main.go --
+package main
+
+import "fmt"
+
+func main() {
+ // Depend on some stdlib function.
+ fmt.Println("In C, 2 + 2 = ", AddC(2, 2))
+ fmt.Println("In C++, 2 + 2 = ", AddCPP(2, 2))
+}
+
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ wd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Copy the workspace to three other directories.
+ // We'll run bazel commands in those directories, not here. We clean those
+ // workspaces at the end of the test, but we don't want to clean this
+ // directory because it's shared with other tests.
+ dirs := []string{wd + "0", wd + "1", wd + "2"}
+ for _, dir := range dirs {
+ if err := copyTree(dir, wd); err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ cmd := bazel_testing.BazelCmd("clean", "--expunge")
+ cmd.Dir = dir
+ cmd.Run()
+ os.RemoveAll(dir)
+ }()
+ }
+ defer func() {
+ var wg sync.WaitGroup
+ wg.Add(len(dirs))
+ for _, dir := range dirs {
+ go func(dir string) {
+ defer wg.Done()
+ cmd := bazel_testing.BazelCmd("clean", "--expunge")
+ cmd.Dir = dir
+ cmd.Run()
+ os.RemoveAll(dir)
+ }(dir)
+ }
+ wg.Wait()
+ }()
+
+ // Change the source file in dir2. We should detect a difference here.
+ hello2Path := filepath.Join(dirs[2], "hello.go")
+ hello2File, err := os.OpenFile(hello2Path, os.O_WRONLY|os.O_APPEND, 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer hello2File.Close()
+ if _, err := hello2File.WriteString(`func init() { fmt.Println("init") }`); err != nil {
+ t.Fatal(err)
+ }
+ if err := hello2File.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ // Build the targets in each directory.
+ var wg sync.WaitGroup
+ wg.Add(len(dirs))
+ for _, dir := range dirs {
+ go func(dir string) {
+ defer wg.Done()
+ cmd := bazel_testing.BazelCmd("build",
+ "//:all",
+ "@io_bazel_rules_go//go/tools/builders:go_path",
+ "@go_sdk//:builder",
+ )
+ cmd.Dir = dir
+ if err := cmd.Run(); err != nil {
+ t.Fatalf("in %s, error running %s: %v", dir, strings.Join(cmd.Args, " "), err)
+ }
+ }(dir)
+ }
+ wg.Wait()
+
+ // Hash files in each bazel-bin directory.
+ dirHashes := make([][]fileHash, len(dirs))
+ errs := make([]error, len(dirs))
+ wg.Add(len(dirs))
+ for i := range dirs {
+ go func(i int) {
+ defer wg.Done()
+ dirHashes[i], errs[i] = hashFiles(filepath.Join(dirs[i], "bazel-bin"))
+ }(i)
+ }
+ wg.Wait()
+ for _, err := range errs {
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ // Compare dir0 and dir1. They should be identical.
+ if err := compareHashes(dirHashes[0], dirHashes[1]); err != nil {
+ t.Fatal(err)
+ }
+
+ // Compare dir0 and dir2. They should be different.
+ if err := compareHashes(dirHashes[0], dirHashes[2]); err == nil {
+ t.Fatalf("dir0 and dir2 are the same)", len(dirHashes[0]))
+ }
+
+ // Check that the go_sdk path doesn't appear in the builder binary. This path is different
+ // nominally different per workspace (but in these tests, the go_sdk paths are all set to the same
+ // path in WORKSPACE) -- so if this path is in the builder binary, then builds between workspaces
+ // would be partially non cacheable.
+ builder_file, err := os.Open(filepath.Join(dirs[0], "bazel-bin", "external", "go_sdk", "builder"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer builder_file.Close()
+ builder_data, err := ioutil.ReadAll(builder_file)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if bytes.Index(builder_data, []byte("go_sdk")) != -1 {
+ t.Fatalf("Found go_sdk path in builder binary, builder tool won't be reproducible")
+ }
+}
+
+func copyTree(dstRoot, srcRoot string) error {
+ return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ rel, err := filepath.Rel(srcRoot, srcPath)
+ if err != nil {
+ return err
+ }
+ var dstPath string
+ if rel == "." {
+ dstPath = dstRoot
+ } else {
+ dstPath = filepath.Join(dstRoot, rel)
+ }
+
+ if info.IsDir() {
+ return os.Mkdir(dstPath, 0777)
+ }
+ r, err := os.Open(srcPath)
+ if err != nil {
+ return nil
+ }
+ defer r.Close()
+ w, err := os.Create(dstPath)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+ if _, err := io.Copy(w, r); err != nil {
+ return err
+ }
+ return w.Close()
+ })
+}
+
+func compareHashes(lhs, rhs []fileHash) error {
+ buf := &bytes.Buffer{}
+ for li, ri := 0, 0; li < len(lhs) || ri < len(rhs); {
+ if li < len(lhs) && (ri == len(rhs) || lhs[li].rel < rhs[ri].rel) {
+ fmt.Fprintf(buf, "%s only in left\n", lhs[li].rel)
+ li++
+ continue
+ }
+ if ri < len(rhs) && (li == len(lhs) || rhs[ri].rel < lhs[li].rel) {
+ fmt.Fprintf(buf, "%s only in right\n", rhs[ri].rel)
+ ri++
+ continue
+ }
+ if lhs[li].hash != rhs[ri].hash {
+ fmt.Fprintf(buf, "%s is different: %s %s\n", lhs[li].rel, lhs[li].hash, rhs[ri].hash)
+ }
+ li++
+ ri++
+ }
+ if errStr := buf.String(); errStr != "" {
+ return errors.New(errStr)
+ }
+ return nil
+}
+
+type fileHash struct {
+ rel, hash string
+}
+
+func hashFiles(dir string) ([]fileHash, error) {
+ // Follow top-level symbolic link
+ root := dir
+ for {
+ info, err := os.Lstat(root)
+ if err != nil {
+ return nil, err
+ }
+ if info.Mode()&os.ModeType != os.ModeSymlink {
+ break
+ }
+ rel, err := os.Readlink(root)
+ if err != nil {
+ return nil, err
+ }
+ if filepath.IsAbs(rel) {
+ root = rel
+ } else {
+ root = filepath.Join(filepath.Dir(dir), rel)
+ }
+ }
+
+ // Gather hashes of files within the tree.
+ var hashes []fileHash
+ var sum [16]byte
+ err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ // Skip directories and symbolic links to directories.
+ if info.Mode()&os.ModeType == os.ModeSymlink {
+ info, err = os.Stat(path)
+ if err != nil {
+ return err
+ }
+ }
+ if info.IsDir() {
+ return nil
+ }
+
+ // Skip MANIFEST, runfiles_manifest, and .lo files.
+ // TODO(jayconrod): find out why .lo files are not reproducible.
+ base := filepath.Base(path)
+ if base == "MANIFEST" || strings.HasSuffix(base, ".runfiles_manifest") || strings.HasSuffix(base, ".lo") {
+ return nil
+ }
+
+ rel, err := filepath.Rel(root, path)
+ if err != nil {
+ return err
+ }
+
+ r, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+ h := sha256.New()
+ if _, err := io.Copy(h, r); err != nil {
+ return err
+ }
+ hashes = append(hashes, fileHash{rel: rel, hash: hex.EncodeToString(h.Sum(sum[:0]))})
+
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return hashes, nil
+}