Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57c1edc4 authored by Yu Liu's avatar Yu Liu Committed by Gerrit Code Review
Browse files

Merge "Support cc code coverage for mixed build"

parents 83a02e43 8d82ac58
Loading
Loading
Loading
Loading
+24 −6
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ type BazelContext interface {

	// Issues commands to Bazel to receive results for all cquery requests
	// queued in the BazelContext.
	InvokeBazel() error
	InvokeBazel(config Config) error

	// Returns true if bazel is enabled for the given configuration.
	BazelEnabled() bool
@@ -191,7 +191,7 @@ func (m MockBazelContext) GetPythonBinary(label string, cfgKey configKey) (strin
	return result, nil
}

func (m MockBazelContext) InvokeBazel() error {
func (m MockBazelContext) InvokeBazel(config Config) error {
	panic("unimplemented")
}

@@ -261,7 +261,7 @@ func (n noopBazelContext) GetPythonBinary(label string, cfgKey configKey) (strin
	panic("unimplemented")
}

func (n noopBazelContext) InvokeBazel() error {
func (n noopBazelContext) InvokeBazel(config Config) error {
	panic("unimplemented")
}

@@ -361,6 +361,7 @@ type bazelCommand struct {
type mockBazelRunner struct {
	bazelCommandResults map[bazelCommand]string
	commands            []bazelCommand
	extraFlags          []string
}

func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
@@ -368,6 +369,7 @@ func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
	command bazelCommand,
	extraFlags ...string) (string, string, error) {
	r.commands = append(r.commands, command)
	r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
	if ret, ok := r.bazelCommandResults[command]; ok {
		return ret, "", nil
	}
@@ -676,7 +678,7 @@ func (p *bazelPaths) outDir() string {

// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
func (context *bazelContext) InvokeBazel() error {
func (context *bazelContext) InvokeBazel(config Config) error {
	context.results = make(map[cqueryKey]string)

	var cqueryOutput string
@@ -759,15 +761,31 @@ func (context *bazelContext) InvokeBazel() error {

	// Issue an aquery command to retrieve action information about the bazel build tree.
	//
	// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
	var aqueryOutput string
	var coverageFlags []string
	if Bool(config.productVariables.ClangCoverage) {
		coverageFlags = append(coverageFlags, "--collect_code_coverage")
		if len(config.productVariables.NativeCoveragePaths) > 0 ||
			len(config.productVariables.NativeCoverageExcludePaths) > 0 {
			includePaths := JoinWithPrefixAndSeparator(config.productVariables.NativeCoveragePaths, "+", ",")
			excludePaths := JoinWithPrefixAndSeparator(config.productVariables.NativeCoverageExcludePaths, "-", ",")
			if len(includePaths) > 0 && len(excludePaths) > 0 {
				includePaths += ","
			}
			coverageFlags = append(coverageFlags, fmt.Sprintf(`--instrumentation_filter=%s`,
				includePaths+excludePaths))
		}
	}

	extraFlags := append([]string{"--output=jsonproto"}, coverageFlags...)

	aqueryOutput, _, err = context.issueBazelCommand(
		context.paths,
		bazel.AqueryBuildRootRunName,
		bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
		// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
		// proto sources, which would add a number of unnecessary dependencies.
		"--output=jsonproto")
		extraFlags...)

	if err != nil {
		return err
+54 −3
Original line number Diff line number Diff line
@@ -4,11 +4,14 @@ import (
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"testing"

	"android/soong/bazel/cquery"
)

var testConfig = TestConfig("out", nil, "", nil)

func TestRequestResultsAfterInvokeBazel(t *testing.T) {
	label := "//foo:bar"
	cfg := configKey{"arm64_armv8-a", Android}
@@ -16,7 +19,7 @@ func TestRequestResultsAfterInvokeBazel(t *testing.T) {
		bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
	})
	bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
	err := bazelContext.InvokeBazel()
	err := bazelContext.InvokeBazel(testConfig)
	if err != nil {
		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
	}
@@ -30,7 +33,7 @@ func TestRequestResultsAfterInvokeBazel(t *testing.T) {

func TestInvokeBazelWritesBazelFiles(t *testing.T) {
	bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
	err := bazelContext.InvokeBazel()
	err := bazelContext.InvokeBazel(testConfig)
	if err != nil {
		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
	}
@@ -86,7 +89,7 @@ func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
  }]
}`,
	})
	err := bazelContext.InvokeBazel()
	err := bazelContext.InvokeBazel(testConfig)
	if err != nil {
		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
	}
@@ -97,6 +100,54 @@ func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
	}
}

func TestCoverageFlagsAfterInvokeBazel(t *testing.T) {
	testConfig.productVariables.ClangCoverage = boolPtr(true)

	testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,+foo2,-bar1,-bar2`)

	testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,-bar1`)

	testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
	testConfig.productVariables.NativeCoverageExcludePaths = nil
	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1`)

	testConfig.productVariables.NativeCoveragePaths = nil
	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=-bar1`)

	testConfig.productVariables.ClangCoverage = boolPtr(false)
	actual := verifyExtraFlags(t, testConfig, ``)
	if strings.Contains(actual, "--collect_code_coverage") ||
		strings.Contains(actual, "--instrumentation_filter=") {
		t.Errorf("Expected code coverage disabled, but got %#v", actual)
	}
}

func verifyExtraFlags(t *testing.T, config Config, expected string) string {
	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})

	err := bazelContext.InvokeBazel(config)
	if err != nil {
		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
	}

	flags := bazelContext.bazelRunner.(*mockBazelRunner).extraFlags
	if expected := 3; len(flags) != expected {
		t.Errorf("Expected %d extra flags got %#v", expected, flags)
	}

	actual := flags[1]
	if !strings.Contains(actual, expected) {
		t.Errorf("Expected %#v got %#v", expected, actual)
	}

	return actual
}

func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
	t.Helper()
	p := bazelPaths{
+7 −1
Original line number Diff line number Diff line
@@ -32,6 +32,12 @@ func CopyOf(s []string) []string {
// JoinWithPrefix prepends the prefix to each string in the list and
// returns them joined together with " " as separator.
func JoinWithPrefix(strs []string, prefix string) string {
	return JoinWithPrefixAndSeparator(strs, prefix, " ")
}

// JoinWithPrefixAndSeparator prepends the prefix to each string in the list and
// returns them joined together with the given separator.
func JoinWithPrefixAndSeparator(strs []string, prefix string, sep string) string {
	if len(strs) == 0 {
		return ""
	}
@@ -40,7 +46,7 @@ func JoinWithPrefix(strs []string, prefix string) string {
	buf.WriteString(prefix)
	buf.WriteString(strs[0])
	for i := 1; i < len(strs); i++ {
		buf.WriteString(" ")
		buf.WriteString(sep)
		buf.WriteString(prefix)
		buf.WriteString(strs[i])
	}
+3 −0
Original line number Diff line number Diff line
@@ -664,6 +664,9 @@ func shouldSkipAction(a action) bool {
	if a.Mnemonic == "FileWrite" {
		return true
	}
	if a.Mnemonic == "BaselineCoverage" {
		return true
	}
	return false
}

+4 −1
Original line number Diff line number Diff line
@@ -959,11 +959,12 @@ func TestCcLibraryFeatures(t *testing.T) {
		"features": `[
        "disable_pack_relocations",
        "-no_undefined_symbols",
        "-coverage",
    ]`,
		"srcs": `["a.cpp"]`,
	})...)
	expected_targets = append(expected_targets, makeCcLibraryTargets("b", attrNameToString{
		"features": `select({
		"features": `["-coverage"] + select({
        "//build/bazel/platforms/arch:x86_64": [
            "disable_pack_relocations",
            "-no_undefined_symbols",
@@ -994,6 +995,7 @@ cc_library {
    pack_relocations: false,
    allow_undefined_symbols: true,
    include_build_directory: false,
    native_coverage: false,
}

cc_library {
@@ -1006,6 +1008,7 @@ cc_library {
        },
    },
    include_build_directory: false,
    native_coverage: false,
}

cc_library {
Loading