blob: 4d885c6de0ad8ab24935f8f9ef6d57135eb02df7 [file] [log] [blame]
// Copyright 2020 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 testing
import (
"path/filepath"
"strconv"
"android/soong/android"
"android/soong/testing/test_spec_proto"
"google.golang.org/protobuf/proto"
"github.com/google/blueprint"
)
// ErrTestModuleDataNotFound is the error message for missing test module provider data.
const ErrTestModuleDataNotFound = "The module '%s' does not provide test specification data. Hint: This issue could arise if either the module is not a valid testing module or if it lacks the required 'TestModuleProviderKey' provider.\n"
func TestSpecFactory() android.Module {
module := &TestSpecModule{}
android.InitAndroidModule(module)
android.InitDefaultableModule(module)
module.AddProperties(&module.properties)
return module
}
type TestSpecModule struct {
android.ModuleBase
android.DefaultableModuleBase
// Properties for "test_spec"
properties struct {
// Specifies the name of the test config.
Name string
// Specifies the team ID.
TeamId string
// Specifies the list of tests covered under this module.
Tests []string
}
}
type testsDepTagType struct {
blueprint.BaseDependencyTag
}
var testsDepTag = testsDepTagType{}
func (module *TestSpecModule) DepsMutator(ctx android.BottomUpMutatorContext) {
// Validate Properties
if len(module.properties.TeamId) == 0 {
ctx.PropertyErrorf("TeamId", "Team Id not found in the test_spec module. Hint: Maybe the TeamId property hasn't been properly specified.")
}
if !isInt(module.properties.TeamId) {
ctx.PropertyErrorf("TeamId", "Invalid value for Team ID. The Team ID must be an integer.")
}
if len(module.properties.Tests) == 0 {
ctx.PropertyErrorf("Tests", "Expected to attribute some test but none found. Hint: Maybe the test property hasn't been properly specified.")
}
ctx.AddDependency(ctx.Module(), testsDepTag, module.properties.Tests...)
}
func isInt(s string) bool {
_, err := strconv.Atoi(s)
return err == nil
}
// Provider published by TestSpec
type TestSpecProviderData struct {
IntermediatePath android.WritablePath
}
var TestSpecProviderKey = blueprint.NewProvider[TestSpecProviderData]()
type TestModuleProviderData struct {
}
var TestModuleProviderKey = blueprint.NewProvider[TestModuleProviderData]()
func (module *TestSpecModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
for _, m := range ctx.GetDirectDepsWithTag(testsDepTag) {
if _, ok := android.OtherModuleProvider(ctx, m, TestModuleProviderKey); !ok {
ctx.ModuleErrorf(ErrTestModuleDataNotFound, m.Name())
}
}
bpFilePath := filepath.Join(ctx.ModuleDir(), ctx.BlueprintsFile())
metadataList := make(
[]*test_spec_proto.TestSpec_OwnershipMetadata, 0,
len(module.properties.Tests),
)
for _, test := range module.properties.Tests {
targetName := test
metadata := test_spec_proto.TestSpec_OwnershipMetadata{
TrendyTeamId: &module.properties.TeamId,
TargetName: &targetName,
Path: &bpFilePath,
}
metadataList = append(metadataList, &metadata)
}
intermediatePath := android.PathForModuleOut(
ctx, "intermediateTestSpecMetadata.pb",
)
testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList}
protoData, err := proto.Marshal(&testSpecMetadata)
if err != nil {
ctx.ModuleErrorf("Error: %s", err.Error())
}
android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData))
android.SetProvider(ctx,
TestSpecProviderKey, TestSpecProviderData{
IntermediatePath: intermediatePath,
},
)
}