Merge pull request #2236 from munnerz/covered-images
Add Bazel image targets with coverage enabled
This commit is contained in:
commit
1793e7b573
3
Makefile
3
Makefile
@ -18,7 +18,8 @@ APP_VERSION := canary
|
||||
HACK_DIR ?= hack
|
||||
|
||||
SKIP_GLOBALS := false
|
||||
GINKGO_SKIP :=
|
||||
# Skip Venafi tests whilst there are issues with the TPP server
|
||||
GINKGO_SKIP := Venafi
|
||||
GINKGO_FOCUS :=
|
||||
|
||||
## e2e test vars
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
load("//hack/build:docker.bzl", "image")
|
||||
load("//hack/build:docker.bzl", "covered_image", "image")
|
||||
|
||||
image(
|
||||
name = "image",
|
||||
@ -8,6 +8,12 @@ image(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
covered_image(
|
||||
name = "image.covered",
|
||||
component = "acmesolver",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["main.go"],
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
load("//hack/build:docker.bzl", "image")
|
||||
load("//hack/build:docker.bzl", "covered_image", "image")
|
||||
|
||||
image(
|
||||
name = "image",
|
||||
@ -8,6 +8,12 @@ image(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
covered_image(
|
||||
name = "image.covered",
|
||||
component = "cainjector",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
load("//hack/build:docker.bzl", "image")
|
||||
load("//hack/build:docker.bzl", "covered_image", "image")
|
||||
|
||||
image(
|
||||
name = "image",
|
||||
@ -8,6 +8,12 @@ image(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
covered_image(
|
||||
name = "image.covered",
|
||||
component = "controller",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
|
||||
@ -135,7 +135,6 @@ func Run(opts *options.ControllerOptions, stopCh <-chan struct{}) {
|
||||
}
|
||||
|
||||
startLeaderElection(rootCtx, opts, leaderElectionClient, ctx.Recorder, run)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func buildControllerContext(ctx context.Context, stopCh <-chan struct{}, opts *options.ControllerOptions) (*controller.Context, *rest.Config, error) {
|
||||
@ -270,7 +269,7 @@ func startLeaderElection(ctx context.Context, opts *options.ControllerOptions, l
|
||||
}
|
||||
|
||||
// Try and become the leader and start controller manager loops
|
||||
leaderelection.RunOrDie(context.TODO(), leaderelection.LeaderElectionConfig{
|
||||
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
|
||||
Lock: &rl,
|
||||
LeaseDuration: opts.LeaderElectionLeaseDuration,
|
||||
RenewDeadline: opts.LeaderElectionRenewDeadline,
|
||||
|
||||
@ -37,7 +37,7 @@ func main() {
|
||||
|
||||
flag.CommandLine.Parse([]string{})
|
||||
if err := cmd.Execute(); err != nil {
|
||||
klog.Fatal(err)
|
||||
klog.Info(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
load("//hack/build:docker.bzl", "image")
|
||||
load("//hack/build:docker.bzl", "covered_image", "image")
|
||||
|
||||
image(
|
||||
name = "image",
|
||||
@ -8,6 +8,12 @@ image(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
covered_image(
|
||||
name = "image.covered",
|
||||
component = "webhook",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["main.go"],
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
load("@io_bazel_rules_docker//container:image.bzl", "container_image")
|
||||
load("@io_bazel_rules_docker//container:bundle.bzl", "container_bundle")
|
||||
load("@io_bazel_rules_docker//go:image.bzl", "go_image")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
def image(
|
||||
name,
|
||||
@ -22,12 +23,14 @@ def image(
|
||||
binary,
|
||||
user = "1000",
|
||||
stamp = True,
|
||||
testonly = False,
|
||||
**kwargs):
|
||||
|
||||
go_image(
|
||||
name = "%s.app" % name,
|
||||
base = "@static_base//image",
|
||||
binary = binary,
|
||||
testonly = testonly,
|
||||
)
|
||||
|
||||
container_image(
|
||||
@ -35,6 +38,7 @@ def image(
|
||||
base = "%s.app" % name,
|
||||
user = user,
|
||||
stamp = stamp,
|
||||
testonly = testonly,
|
||||
**kwargs)
|
||||
|
||||
container_bundle(
|
||||
@ -42,4 +46,47 @@ def image(
|
||||
images = {
|
||||
component + ":{STABLE_APP_GIT_COMMIT}": ":" + name,
|
||||
},
|
||||
testonly = testonly,
|
||||
)
|
||||
|
||||
def covered_image(name, component, **kwargs):
|
||||
native.genrule(
|
||||
name = "%s.covered-testfile" % name,
|
||||
cmd = """
|
||||
name="%s";
|
||||
cat <<EOF > "$@"
|
||||
package main
|
||||
import (
|
||||
"testing"
|
||||
"github.com/jetstack/cert-manager/pkg/util/coverage"
|
||||
)
|
||||
func TestMain(m *testing.M) {
|
||||
// Get coverage running
|
||||
coverage.InitCoverage("$${name}")
|
||||
// Go!
|
||||
main()
|
||||
// Make sure we actually write the profiling information to disk, if we make it here.
|
||||
// On long-running services, or anything that calls os.Exit(), this is insufficient,
|
||||
// so we also flush periodically with a default period of five seconds (configurable by
|
||||
// the COVERAGE_FLUSH_INTERVAL environment variable).
|
||||
coverage.FlushCoverage()
|
||||
}
|
||||
EOF
|
||||
""" % component,
|
||||
outs = ["main_test.go"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "%s.covered-app" % name,
|
||||
srcs = ["main_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//pkg/util/coverage:go_default_library"],
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
image(
|
||||
name = name,
|
||||
binary = "%s.covered-app" % name,
|
||||
testonly = True,
|
||||
component = component,
|
||||
**kwargs)
|
||||
|
||||
@ -37,6 +37,7 @@ filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/util/coverage:all-srcs",
|
||||
"//pkg/util/errors:all-srcs",
|
||||
"//pkg/util/feature:all-srcs",
|
||||
"//pkg/util/kube:all-srcs",
|
||||
|
||||
29
pkg/util/coverage/BUILD.bazel
Normal file
29
pkg/util/coverage/BUILD.bazel
Normal file
@ -0,0 +1,29 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"coverage.go",
|
||||
"faketestdeps.go",
|
||||
],
|
||||
importpath = "github.com/jetstack/cert-manager/pkg/util/coverage",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"@io_k8s_apimachinery//pkg/util/wait:go_default_library",
|
||||
"@io_k8s_klog//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
90
pkg/util/coverage/coverage.go
Normal file
90
pkg/util/coverage/coverage.go
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2019 The Jetstack cert-manager contributors.
|
||||
|
||||
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 coverage provides tools for coverage-instrumented binaries to collect and
|
||||
// flush coverage information.
|
||||
package coverage
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
var coverageFile string
|
||||
|
||||
// tempCoveragePath returns a temporary file to write coverage information to.
|
||||
// The file is in the same directory as the destination, ensuring os.Rename will work.
|
||||
func tempCoveragePath() string {
|
||||
return coverageFile + ".tmp"
|
||||
}
|
||||
|
||||
// InitCoverage is called from the dummy unit test to prepare Go's coverage framework.
|
||||
// Clients should never need to call it.
|
||||
func InitCoverage(name string) {
|
||||
// We read the coverage destination in from the COVERPROFILE env var,
|
||||
// or if it's empty we just use a default in /tmp
|
||||
coverageFile = os.Getenv("COVERPROFILE")
|
||||
if coverageFile == "" {
|
||||
coverageFile = "/tmp/cm-" + name + ".cov"
|
||||
}
|
||||
fmt.Println("Dumping coverage information to " + coverageFile)
|
||||
|
||||
flushInterval := 5 * time.Second
|
||||
requestedInterval := os.Getenv("COVERAGE_FLUSH_INTERVAL")
|
||||
if requestedInterval != "" {
|
||||
if duration, err := time.ParseDuration(requestedInterval); err == nil {
|
||||
flushInterval = duration
|
||||
} else {
|
||||
panic("Invalid COVERAGE_FLUSH_INTERVAL value; try something like '30s'.")
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the unit test framework with the required arguments to activate test coverage.
|
||||
flag.CommandLine.Parse([]string{"-test.coverprofile", tempCoveragePath()})
|
||||
|
||||
// Begin periodic logging
|
||||
go wait.Forever(FlushCoverage, flushInterval)
|
||||
}
|
||||
|
||||
// FlushCoverage flushes collected coverage information to disk.
|
||||
// The destination file is configured at startup and cannot be changed.
|
||||
// Calling this function also sends a line like "coverage: 5% of statements" to stdout.
|
||||
func FlushCoverage() {
|
||||
// We're not actually going to run any tests, but we need Go to think we did so it writes
|
||||
// coverage information to disk. To achieve this, we create a bunch of empty test suites and
|
||||
// have it "run" them.
|
||||
tests := []testing.InternalTest{}
|
||||
benchmarks := []testing.InternalBenchmark{}
|
||||
examples := []testing.InternalExample{}
|
||||
|
||||
var deps fakeTestDeps
|
||||
|
||||
dummyRun := testing.MainStart(deps, tests, benchmarks, examples)
|
||||
dummyRun.Run()
|
||||
|
||||
// Once it writes to the temporary path, we move it to the intended path.
|
||||
// This gets us atomic updates from the perspective of another process trying to access
|
||||
// the file.
|
||||
if err := os.Rename(tempCoveragePath(), coverageFile); err != nil {
|
||||
klog.Errorf("Couldn't move coverage file from %s to %s", coverageFile, tempCoveragePath())
|
||||
}
|
||||
}
|
||||
54
pkg/util/coverage/faketestdeps.go
Normal file
54
pkg/util/coverage/faketestdeps.go
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2019 The Jetstack cert-manager contributors.
|
||||
|
||||
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 coverage
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// This is an implementation of testing.testDeps. It doesn't need to do anything, because
|
||||
// no tests are actually run. It does need a concrete implementation of at least ImportPath,
|
||||
// which is called unconditionally when running tests.
|
||||
type fakeTestDeps struct{}
|
||||
|
||||
func (fakeTestDeps) ImportPath() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (fakeTestDeps) MatchString(pat, str string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (fakeTestDeps) StartCPUProfile(io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fakeTestDeps) StopCPUProfile() {}
|
||||
|
||||
func (fakeTestDeps) StartTestLog(io.Writer) {}
|
||||
|
||||
func (fakeTestDeps) StopTestLog() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fakeTestDeps) WriteHeapProfile(io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fakeTestDeps) WriteProfileTo(string, io.Writer, int) error {
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user