1// Copyright 2020 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package testing 16 17import ( 18 "path/filepath" 19 "strconv" 20 21 "android/soong/android" 22 "android/soong/testing/test_spec_proto" 23 "google.golang.org/protobuf/proto" 24 25 "github.com/google/blueprint" 26) 27 28// ErrTestModuleDataNotFound is the error message for missing test module provider data. 29const 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" 30 31func TestSpecFactory() android.Module { 32 module := &TestSpecModule{} 33 34 android.InitAndroidModule(module) 35 android.InitDefaultableModule(module) 36 module.AddProperties(&module.properties) 37 38 return module 39} 40 41type TestSpecModule struct { 42 android.ModuleBase 43 android.DefaultableModuleBase 44 45 // Properties for "test_spec" 46 properties struct { 47 // Specifies the name of the test config. 48 Name string 49 // Specifies the team ID. 50 TeamId string 51 // Specifies the list of tests covered under this module. 52 Tests []string 53 } 54} 55 56type testsDepTagType struct { 57 blueprint.BaseDependencyTag 58} 59 60var testsDepTag = testsDepTagType{} 61 62func (module *TestSpecModule) DepsMutator(ctx android.BottomUpMutatorContext) { 63 // Validate Properties 64 if len(module.properties.TeamId) == 0 { 65 ctx.PropertyErrorf("TeamId", "Team Id not found in the test_spec module. Hint: Maybe the TeamId property hasn't been properly specified.") 66 } 67 if !isInt(module.properties.TeamId) { 68 ctx.PropertyErrorf("TeamId", "Invalid value for Team ID. The Team ID must be an integer.") 69 } 70 if len(module.properties.Tests) == 0 { 71 ctx.PropertyErrorf("Tests", "Expected to attribute some test but none found. Hint: Maybe the test property hasn't been properly specified.") 72 } 73 ctx.AddDependency(ctx.Module(), testsDepTag, module.properties.Tests...) 74} 75func isInt(s string) bool { 76 _, err := strconv.Atoi(s) 77 return err == nil 78} 79 80// Provider published by TestSpec 81type TestSpecProviderData struct { 82 IntermediatePath android.WritablePath 83} 84 85var TestSpecProviderKey = blueprint.NewProvider[TestSpecProviderData]() 86 87type TestModuleProviderData struct { 88} 89 90var TestModuleProviderKey = blueprint.NewProvider[TestModuleProviderData]() 91 92func (module *TestSpecModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 93 for _, m := range ctx.GetDirectDepsWithTag(testsDepTag) { 94 if _, ok := android.OtherModuleProvider(ctx, m, TestModuleProviderKey); !ok { 95 ctx.ModuleErrorf(ErrTestModuleDataNotFound, m.Name()) 96 } 97 } 98 bpFilePath := filepath.Join(ctx.ModuleDir(), ctx.BlueprintsFile()) 99 metadataList := make( 100 []*test_spec_proto.TestSpec_OwnershipMetadata, 0, 101 len(module.properties.Tests), 102 ) 103 for _, test := range module.properties.Tests { 104 targetName := test 105 metadata := test_spec_proto.TestSpec_OwnershipMetadata{ 106 TrendyTeamId: &module.properties.TeamId, 107 TargetName: &targetName, 108 Path: &bpFilePath, 109 } 110 metadataList = append(metadataList, &metadata) 111 } 112 intermediatePath := android.PathForModuleOut( 113 ctx, "intermediateTestSpecMetadata.pb", 114 ) 115 testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList} 116 protoData, err := proto.Marshal(&testSpecMetadata) 117 if err != nil { 118 ctx.ModuleErrorf("Error: %s", err.Error()) 119 } 120 android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData)) 121 122 android.SetProvider(ctx, 123 TestSpecProviderKey, TestSpecProviderData{ 124 IntermediatePath: intermediatePath, 125 }, 126 ) 127} 128