Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go_test: change directory before use init() functions run #2696

Merged
merged 6 commits into from
Oct 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ load(
# gazelle:exclude go/tools/coverdata
# gazelle:exclude go/tools/fetch_repo
# gazelle:exclude go/tools/windows-testrunner
# gazelle:exclude go/tools/testinit
# gazelle:exclude go/tools/testwrapper
# gazelle:go_naming_convention import_alias

Expand Down
13 changes: 8 additions & 5 deletions go/private/rules/test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ def _go_test_impl(ctx):

main_go = go.declare_file(go, path = "testmain.go")
arguments = go.builder_args(go, "gentestmain")
arguments.add("-rundir", run_dir)
arguments.add("-output", main_go)
if ctx.configuration.coverage_enabled:
arguments.add("-coverage")
Expand All @@ -115,16 +114,16 @@ def _go_test_impl(ctx):
mnemonic = "GoTestGenTest",
executable = go.toolchain._builder,
arguments = [arguments],
env = {
"RUNDIR": ctx.label.package,
},
)

test_gc_linkopts = gc_linkopts(ctx)
if not go.mode.debug:
# Disable symbol table and DWARF generation for test binaries.
test_gc_linkopts.extend(["-s", "-w"])

# Link in the run_dir global for testinit
test_gc_linkopts.extend(["-X", "github.com/bazelbuild/rules_go/go/tools/testinit.RunDir=" + run_dir])

# Now compile the test binary itself
test_library = GoLibrary(
name = go._ctx.label.name + "~testmain",
Expand All @@ -136,7 +135,7 @@ def _go_test_impl(ctx):
is_main = True,
resolve = None,
)
test_deps = external_archive.direct + [external_archive]
test_deps = external_archive.direct + [external_archive] + ctx.attr._testmain_additional_deps
if ctx.configuration.coverage_enabled:
test_deps.append(go.coverdata)
test_source = go.library_to_source(go, struct(
Expand Down Expand Up @@ -200,6 +199,10 @@ _go_test_kwargs = {
default = ["@io_bazel_rules_go//go/tools/testwrapper:srcs"],
allow_files = go_exts,
),
"_testmain_additional_deps": attr.label_list(
providers = [GoLibrary],
default = ["@io_bazel_rules_go//go/tools/testinit"],
),
# Workaround for bazelbuild/bazel#6293. See comment in lcov_merger.sh.
"_lcov_merger": attr.label(
executable = True,
Expand Down
1 change: 1 addition & 0 deletions go/tools/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ filegroup(
"//go/tools/bazel_testing:all_files",
"//go/tools/builders:all_files",
"//go/tools/coverdata:all_files",
"//go/tools/testinit:all_files",
"//go/tools/testwrapper:all_files",
],
visibility = ["//visibility:public"],
Expand Down
31 changes: 8 additions & 23 deletions go/tools/builders/generate_test_main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"go/parser"
"go/token"
"os"
"path/filepath"
"sort"
"strings"
"text/template"
Expand All @@ -50,7 +49,6 @@ type Example struct {

// Cases holds template data.
type Cases struct {
RunDir string
Imports []*Import
Tests []TestCase
Benchmarks []TestCase
Expand All @@ -62,13 +60,19 @@ type Cases struct {

const testMainTpl = `
package main
// This package must be initialized before packages being tested.
// NOTE: this relies on the order of package initialization, which is the spec
// is somewhat unclear about-- it only clearly guarantees that imported packages
// are initialized before their importers, though in practice (and implied) it
// also respects declaration order, which we're relying on here.
import (
_ "github.com/bazelbuild/rules_go/go/tools/testinit"
)
import (
"flag"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"testing"
"testing/internal/testdeps"
Expand Down Expand Up @@ -131,23 +135,6 @@ func main() {
}
}

// Check if we're being run by Bazel and change directories if so.
// TEST_SRCDIR and TEST_WORKSPACE are set by the Bazel test runner, so that makes a decent proxy.
testSrcdir := os.Getenv("TEST_SRCDIR")
testWorkspace := os.Getenv("TEST_WORKSPACE")
if testSrcdir != "" && testWorkspace != "" {
abs := filepath.Join(testSrcdir, testWorkspace, {{printf "%q" .RunDir}})
err := os.Chdir(abs)
// Ignore the Chdir err when on Windows, since it might have have runfiles symlinks.
// https://github.com/bazelbuild/rules_go/pull/1721#issuecomment-422145904
if err != nil && runtime.GOOS != "windows" {
log.Fatalf("could not change to test directory: %v", err)
}
if err == nil {
os.Setenv("PWD", abs)
}
}

m := testing.MainStart(testdeps.TestDeps{}, testsInShard(), benchmarks, examples)

if filter := os.Getenv("TESTBRIDGE_TEST_ONLY"); filter != "" {
Expand Down Expand Up @@ -183,7 +170,6 @@ func genTestMain(args []string) error {
sources := multiFlag{}
flags := flag.NewFlagSet("GoTestGenTest", flag.ExitOnError)
goenv := envFlags(flags)
runDir := flags.String("rundir", ".", "Path to directory where tests should run.")
out := flags.String("output", "", "output file to write. Defaults to stdout.")
coverage := flags.Bool("coverage", false, "whether coverage is supported")
pkgname := flags.String("pkgname", "", "package name of test")
Expand Down Expand Up @@ -235,7 +221,6 @@ func genTestMain(args []string) error {
}

cases := Cases{
RunDir: strings.Replace(filepath.FromSlash(*runDir), `\`, `\\`, -1),
Coverage: *coverage,
Pkgname: *pkgname,
}
Expand Down
15 changes: 15 additions & 0 deletions go/tools/testinit/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go/private/rules:library.bzl", "go_tool_library")

go_tool_library(
name = "testinit",
srcs = ["testinit.go"],
importpath = "github.com/bazelbuild/rules_go/go/tools/testinit",
visibility = ["//visibility:public"],
)

filegroup(
name = "all_files",
testonly = True,
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
56 changes: 56 additions & 0 deletions go/tools/testinit/testinit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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 testinit

// This package must have no deps beyond Go SDK.
import (
"log"
"os"
"path/filepath"
"runtime"
)

var (
// Initialized by linker.
RunDir string
)

// This initializer runs before any user packages.
func init() {
// Check if we're being run by Bazel and change directories if so.
// TEST_SRCDIR and TEST_WORKSPACE are set by the Bazel test runner, so that makes a decent proxy.
testSrcdir, hasSrcDir := os.LookupEnv("TEST_SRCDIR")
testWorkspace, hasWorkspace := os.LookupEnv("TEST_WORKSPACE")
if hasSrcDir && hasWorkspace && RunDir != "" {
abs := RunDir
if !filepath.IsAbs(RunDir) {
abs = filepath.Join(testSrcdir, testWorkspace, RunDir)
}
err := os.Chdir(abs)
// Ignore the Chdir err when on Windows, since it might have have runfiles symlinks.
// https://github.com/bazelbuild/rules_go/pull/1721#issuecomment-422145904
if err != nil && runtime.GOOS != "windows" {
log.Fatalf("could not change to test directory: %v", err)
}
if err == nil {
_ = os.Setenv("PWD", abs)
}
}

// Setup the bazel tmpdir as the go tmpdir.
if tmpDir, ok := os.LookupEnv("TEST_TMPDIR"); ok {
_ = os.Setenv("TMPDIR", tmpDir)
}
}