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

Commit 98d46751 authored by Ronald Braunstein's avatar Ronald Braunstein Committed by Gerrit Code Review
Browse files

Merge "Add test-only and test-target fields to all_teams proto." into main

parents c63c4306 c560309e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ bootstrap_go_package {
        "sandbox.go",
        "sdk.go",
        "sdk_version.go",
        "shared_properties.go",
        "singleton.go",
        "singleton_module.go",
        "soong_config_modules.go",
@@ -102,6 +103,7 @@ bootstrap_go_package {
        "visibility.go",
    ],
    testSrcs: [
        "all_teams_test.go",
        "android_test.go",
        "androidmk_test.go",
        "apex_test.go",
+59 −47
Original line number Diff line number Diff line
@@ -23,9 +23,18 @@ func registerAllTeamBuildComponents(ctx RegistrationContext) {
}

// For each module, list the team or the bpFile the module is defined in.
type moduleTeamInfo struct {
type moduleTeamAndTestInfo struct {
	// Name field from bp file for the team
	teamName string
	// Blueprint file the module is located in.
	bpFile string
	// Is this module only used by tests.
	testOnly bool
	// Is this a directly testable target by running the module directly
	// or via tradefed.
	topLevelTestTarget bool
	// String name indicating the module, like `java_library` for reporting.
	kind string
}

type allTeamsSingleton struct {
@@ -37,16 +46,16 @@ type allTeamsSingleton struct {
	// Map of all team modules we visit during GenerateBuildActions
	teams map[string]teamProperties
	// Keeps track of team information or bp file for each module we visit.
	teams_for_mods map[string]moduleTeamInfo
	teams_for_mods map[string]moduleTeamAndTestInfo
}

// See if there is a package module for the given bpFilePath with a team defined, if so return the team.
// If not ascend up to the parent directory and do the same.
func (this *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) {
func (t *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) {
	// return the Default_team listed in the package if is there.
	if p, ok := this.packages[bpFilePath]; ok {
		if t := p.Default_team; t != nil {
			return this.teams[*p.Default_team], true
	if p, ok := t.packages[bpFilePath]; ok {
		if defaultTeam := p.Default_team; defaultTeam != nil {
			return t.teams[*defaultTeam], true
		}
	}
	// Strip a directory and go up.
@@ -57,72 +66,79 @@ func (this *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamPropert
	if current == "." {
		return teamProperties{}, false
	}
	return this.lookupDefaultTeam(filepath.Join(parent, base))
	return t.lookupDefaultTeam(filepath.Join(parent, base))
}

// Create a rule to run a tool to collect all the intermediate files
// which list the team per module into one proto file.
func (this *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) {
	this.packages = make(map[string]packageProperties)
	this.teams = make(map[string]teamProperties)
	this.teams_for_mods = make(map[string]moduleTeamInfo)
// Visit all modules and collect all teams and use WriteFileRuleVerbatim
// to write it out.
func (t *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) {
	t.packages = make(map[string]packageProperties)
	t.teams = make(map[string]teamProperties)
	t.teams_for_mods = make(map[string]moduleTeamAndTestInfo)

	ctx.VisitAllModules(func(module Module) {
		bpFile := ctx.BlueprintFile(module)

		testModInfo := TestModuleInformation{}
		if tmi, ok := SingletonModuleProvider(ctx, module, TestOnlyProviderKey); ok {
			testModInfo = tmi
		}

		// Package Modules and Team Modules are stored in a map so we can look them up by name for
		// modules without a team.
		if pack, ok := module.(*packageModule); ok {
			// Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in this context.
			// Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in t context.
			pkgKey := bpFile
			this.packages[pkgKey] = pack.properties
			t.packages[pkgKey] = pack.properties
			return
		}
		if team, ok := module.(*teamModule); ok {
			this.teams[team.Name()] = team.properties
			t.teams[team.Name()] = team.properties
			return
		}

		// If a team name is given for a module, store it.
		// Otherwise store the bpFile so we can do a package walk later.
		if module.base().Team() != "" {
			this.teams_for_mods[module.Name()] = moduleTeamInfo{teamName: module.base().Team(), bpFile: bpFile}
		} else {
			this.teams_for_mods[module.Name()] = moduleTeamInfo{bpFile: bpFile}
		entry := moduleTeamAndTestInfo{
			bpFile:             bpFile,
			testOnly:           testModInfo.TestOnly,
			topLevelTestTarget: testModInfo.TopLevelTarget,
			kind:               ctx.ModuleType(module),
			teamName:           module.base().Team(),
		}
		t.teams_for_mods[module.Name()] = entry

	})

	// Visit all modules again and lookup the team name in the package or parent package if the team
	// isn't assignged at the module level.
	allTeams := this.lookupTeamForAllModules()
	allTeams := t.lookupTeamForAllModules()

	this.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile)
	t.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile)
	data, err := proto.Marshal(allTeams)
	if err != nil {
		ctx.Errorf("Unable to marshal team data. %s", err)
	}

	WriteFileRuleVerbatim(ctx, this.outputPath, string(data))
	ctx.Phony("all_teams", this.outputPath)
	WriteFileRuleVerbatim(ctx, t.outputPath, string(data))
	ctx.Phony("all_teams", t.outputPath)
}

func (this *allTeamsSingleton) MakeVars(ctx MakeVarsContext) {
	ctx.DistForGoal("all_teams", this.outputPath)
func (t *allTeamsSingleton) MakeVars(ctx MakeVarsContext) {
	ctx.DistForGoal("all_teams", t.outputPath)
}

// Visit every (non-package, non-team) module and write out a proto containing
// either the declared team data for that module or the package default team data for that module.
func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
	teamsProto := make([]*team_proto.Team, len(this.teams_for_mods))
	for i, moduleName := range SortedKeys(this.teams_for_mods) {
		m, _ := this.teams_for_mods[moduleName]
func (t *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
	teamsProto := make([]*team_proto.Team, len(t.teams_for_mods))
	for i, moduleName := range SortedKeys(t.teams_for_mods) {
		m, _ := t.teams_for_mods[moduleName]
		teamName := m.teamName
		var teamProperties teamProperties
		found := false
		if teamName != "" {
			teamProperties, found = this.teams[teamName]
			teamProperties, found = t.teams[teamName]
		} else {
			teamProperties, found = this.lookupDefaultTeam(m.bpFile)
			teamProperties, found = t.lookupDefaultTeam(m.bpFile)
		}

		trendy_team_id := ""
@@ -130,22 +146,18 @@ func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
			trendy_team_id = *teamProperties.Trendy_team_id
		}

		var files []string
		teamData := new(team_proto.Team)
		if trendy_team_id != "" {
		*teamData = team_proto.Team{
				TrendyTeamId: proto.String(trendy_team_id),
			TargetName:     proto.String(moduleName),
			Path:           proto.String(m.bpFile),
				File:         files,
			TestOnly:       proto.Bool(m.testOnly),
			TopLevelTarget: proto.Bool(m.topLevelTestTarget),
			Kind:           proto.String(m.kind),
		}
		if trendy_team_id != "" {
			teamData.TrendyTeamId = proto.String(trendy_team_id)
		} else {
			// Clients rely on the TrendyTeamId optional field not being set.
			*teamData = team_proto.Team{
				TargetName: proto.String(moduleName),
				Path:       proto.String(m.bpFile),
				File:       files,
			}
		}
		teamsProto[i] = teamData
	}
+56 −7
Original line number Diff line number Diff line
@@ -24,9 +24,8 @@ import (
func TestAllTeams(t *testing.T) {
	t.Parallel()
	ctx := GroupFixturePreparers(
		PrepareForTestWithTeamBuildComponents,
		prepareForTestWithTeamAndFakes,
		FixtureRegisterWithContext(func(ctx RegistrationContext) {
			ctx.RegisterModuleType("fake", fakeModuleFactory)
			ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
		}),
	).RunTestWithBp(t, `
@@ -51,6 +50,12 @@ func TestAllTeams(t *testing.T) {

		fake {
			name: "noteam",
                        test_only: true,
		}
		fake {
			name: "test-and-team-and-top",
                        test_only: true,
                        team: "team2",
		}
	`)

@@ -59,16 +64,31 @@ func TestAllTeams(t *testing.T) {

	// map of module name -> trendy team name.
	actualTeams := make(map[string]*string)
	actualTests := []string{}
	actualTopLevelTests := []string{}

	for _, teamProto := range teams.Teams {
		actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId
		if teamProto.GetTestOnly() {
			actualTests = append(actualTests, teamProto.GetTargetName())
		}
		if teamProto.GetTopLevelTarget() {
			actualTopLevelTests = append(actualTopLevelTests, teamProto.GetTargetName())
		}
	}
	expectedTeams := map[string]*string{
		"main_test":             proto.String("cool_team"),
		"tool":                  proto.String("22222"),
		"test-and-team-and-top": proto.String("22222"),
		"noteam":                nil,
	}

	expectedTests := []string{
		"noteam",
		"test-and-team-and-top",
	}
	AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
	AssertDeepEquals(t, "test matchup", expectedTests, actualTests)
}

func getTeamProtoOutput(t *testing.T, ctx *TestResult) *team_proto.AllTeams {
@@ -171,10 +191,9 @@ func TestPackageLookup(t *testing.T) {
		} `

	ctx := GroupFixturePreparers(
		PrepareForTestWithTeamBuildComponents,
		prepareForTestWithTeamAndFakes,
		PrepareForTestWithPackageModule,
		FixtureRegisterWithContext(func(ctx RegistrationContext) {
			ctx.RegisterModuleType("fake", fakeModuleFactory)
			ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
		}),
		FixtureAddTextFile("Android.bp", rootBp),
@@ -206,3 +225,33 @@ func TestPackageLookup(t *testing.T) {
	}
	AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
}

type fakeForTests struct {
	ModuleBase

	sourceProperties SourceProperties
}

func fakeFactory() Module {
	module := &fakeForTests{}
	module.AddProperties(&module.sourceProperties)
	InitAndroidModule(module)

	return module
}

var prepareForTestWithTeamAndFakes = GroupFixturePreparers(
	FixtureRegisterWithContext(RegisterTeamBuildComponents),
	FixtureRegisterWithContext(func(ctx RegistrationContext) {
		ctx.RegisterModuleType("fake", fakeFactory)
	}),
)

func (f *fakeForTests) GenerateAndroidBuildActions(ctx ModuleContext) {
	if Bool(f.sourceProperties.Test_only) {
		SetProvider(ctx, TestOnlyProviderKey, TestModuleInformation{
			TestOnly:       Bool(f.sourceProperties.Test_only),
			TopLevelTarget: false,
		})
	}
}
+26 −0
Original line number Diff line number Diff line
// Copyright 2024 Google Inc. 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 android

// For storing user-supplied properties about source code on a module to be queried later.
type SourceProperties struct {
	// Indicates that the module and its source code are only used in tests, not
	// production code. Used by coverage reports and potentially other tools.
	Test_only *bool
	// Used internally to write if this is a top level test target.
	// i.e. something that can be run directly or through tradefed as a test.
	// `java_library` would be false, `java_test` would be true.
	Top_level_test_target bool `blueprint:"mutated"`
}
+9 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@

package android

import "github.com/google/blueprint"

func init() {
	RegisterTeamBuildComponents(InitRegistrationContext)
}
@@ -37,6 +39,13 @@ type teamModule struct {
	properties teamProperties
}

type TestModuleInformation struct {
	TestOnly       bool
	TopLevelTarget bool
}

var TestOnlyProviderKey = blueprint.NewProvider[TestModuleInformation]()

// Real work is done for the module that depends on us.
// If needed, the team can serialize the config to json/proto file as well.
func (t *teamModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
Loading