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

Commit 8d82ac58 authored by Yu Liu's avatar Yu Liu
Browse files

Support cc code coverage for mixed build

Bug: 231322627
Test: Manual tests and unit tests
Change-Id: I786042af0d612192c54c3572f63a86a47174a242
parent 97fd87e4
Loading
Loading
Loading
Loading
+24 −6
Original line number Original line Diff line number Diff line
@@ -111,7 +111,7 @@ type BazelContext interface {


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


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


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


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


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


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


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


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


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


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


	"android/soong/bazel/cquery"
	"android/soong/bazel/cquery"
)
)


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

func TestRequestResultsAfterInvokeBazel(t *testing.T) {
func TestRequestResultsAfterInvokeBazel(t *testing.T) {
	label := "//foo:bar"
	label := "//foo:bar"
	cfg := configKey{"arm64_armv8-a", Android}
	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`,
		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)
	bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
	err := bazelContext.InvokeBazel()
	err := bazelContext.InvokeBazel(testConfig)
	if err != nil {
	if err != nil {
		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
		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) {
func TestInvokeBazelWritesBazelFiles(t *testing.T) {
	bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
	bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
	err := bazelContext.InvokeBazel()
	err := bazelContext.InvokeBazel(testConfig)
	if err != nil {
	if err != nil {
		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
		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 {
	if err != nil {
		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
		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) {
func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
	t.Helper()
	t.Helper()
	p := bazelPaths{
	p := bazelPaths{
+7 −1
Original line number Original line 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
// JoinWithPrefix prepends the prefix to each string in the list and
// returns them joined together with " " as separator.
// returns them joined together with " " as separator.
func JoinWithPrefix(strs []string, prefix string) string {
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 {
	if len(strs) == 0 {
		return ""
		return ""
	}
	}
@@ -40,7 +46,7 @@ func JoinWithPrefix(strs []string, prefix string) string {
	buf.WriteString(prefix)
	buf.WriteString(prefix)
	buf.WriteString(strs[0])
	buf.WriteString(strs[0])
	for i := 1; i < len(strs); i++ {
	for i := 1; i < len(strs); i++ {
		buf.WriteString(" ")
		buf.WriteString(sep)
		buf.WriteString(prefix)
		buf.WriteString(prefix)
		buf.WriteString(strs[i])
		buf.WriteString(strs[i])
	}
	}
+3 −0
Original line number Original line Diff line number Diff line
@@ -659,6 +659,9 @@ func shouldSkipAction(a action) bool {
	if a.Mnemonic == "FileWrite" {
	if a.Mnemonic == "FileWrite" {
		return true
		return true
	}
	}
	if a.Mnemonic == "BaselineCoverage" {
		return true
	}
	return false
	return false
}
}


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


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


cc_library {
cc_library {
Loading