blob: 65cd5a836fdd773e9ce3668ebe7e13c353d68c11 [file] [log] [blame]
Liz Kammer8d62a4f2021-04-08 09:47:28 -04001package android
2
3import (
Jason Wu118fd2b2022-10-27 18:41:15 +00004 "encoding/json"
Liz Kammer8d62a4f2021-04-08 09:47:28 -04005 "os"
6 "path/filepath"
7 "reflect"
Yu Liu8d82ac52022-05-17 15:13:28 -07008 "strings"
Liz Kammer8d62a4f2021-04-08 09:47:28 -04009 "testing"
Chris Parsonsf874e462022-05-10 13:50:12 -040010
Chris Parsonsc9089dc2023-04-24 16:21:27 +000011 "android/soong/bazel"
Chris Parsonsf874e462022-05-10 13:50:12 -040012 "android/soong/bazel/cquery"
Jason Wu118fd2b2022-10-27 18:41:15 +000013 analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
Jingwen Chenf3b1ec32022-11-07 15:02:48 +000014
Liz Kammer690fbac2023-02-10 11:11:17 -050015 "github.com/google/blueprint/metrics"
Jingwen Chenf3b1ec32022-11-07 15:02:48 +000016 "google.golang.org/protobuf/proto"
Liz Kammer8d62a4f2021-04-08 09:47:28 -040017)
18
Yu Liu8d82ac52022-05-17 15:13:28 -070019var testConfig = TestConfig("out", nil, "", nil)
20
Liz Kammer690fbac2023-02-10 11:11:17 -050021type testInvokeBazelContext struct{}
22
Chris Parsonsc9089dc2023-04-24 16:21:27 +000023type mockBazelRunner struct {
24 testHelper *testing.T
25 // Stores mock behavior. If an issueBazelCommand request is made for command
26 // k, and {k:v} is present in this map, then the mock will return v.
27 bazelCommandResults map[bazelCommand]string
28 // Requests actually made of the mockBazelRunner with issueBazelCommand,
29 // keyed by the command they represent.
30 bazelCommandRequests map[bazelCommand]bazel.CmdRequest
31}
32
33func (r *mockBazelRunner) bazelCommandForRequest(cmdRequest bazel.CmdRequest) bazelCommand {
34 for _, arg := range cmdRequest.Argv {
35 for _, cmdType := range allBazelCommands {
36 if arg == cmdType.command {
37 return cmdType
38 }
39 }
40 }
41 r.testHelper.Fatalf("Unrecognized bazel request: %s", cmdRequest)
42 return cqueryCmd
43}
44
45func (r *mockBazelRunner) issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (string, string, error) {
46 command := r.bazelCommandForRequest(cmdRequest)
47 r.bazelCommandRequests[command] = cmdRequest
48 return r.bazelCommandResults[command], "", nil
49}
50
Liz Kammer690fbac2023-02-10 11:11:17 -050051func (t *testInvokeBazelContext) GetEventHandler() *metrics.EventHandler {
52 return &metrics.EventHandler{}
53}
54
Liz Kammer8d62a4f2021-04-08 09:47:28 -040055func TestRequestResultsAfterInvokeBazel(t *testing.T) {
Yu Liue4312402023-01-18 09:15:31 -080056 label_foo := "@//foo:foo"
57 label_bar := "@//foo:bar"
58 apexKey := ApexConfigKey{
59 WithinApex: true,
60 ApexSdkVersion: "29",
Spandan Das40b79f82023-06-25 20:56:06 +000061 ApiDomain: "myapex",
Yu Liue4312402023-01-18 09:15:31 -080062 }
63 cfg_foo := configKey{"arm64_armv8-a", Android, apexKey}
64 cfg_bar := configKey{arch: "arm64_armv8-a", osType: Android}
65 cmd_results := []string{
Spandan Das40b79f82023-06-25 20:56:06 +000066 `@//foo:foo|arm64_armv8-a|android|within_apex|29|myapex>>out/foo/foo.txt`,
Yu Liue4312402023-01-18 09:15:31 -080067 `@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
68 }
Chris Parsonsc9089dc2023-04-24 16:21:27 +000069 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{cqueryCmd: strings.Join(cmd_results, "\n")})
Yu Liue4312402023-01-18 09:15:31 -080070
71 bazelContext.QueueBazelRequest(label_foo, cquery.GetOutputFiles, cfg_foo)
72 bazelContext.QueueBazelRequest(label_bar, cquery.GetOutputFiles, cfg_bar)
Liz Kammer690fbac2023-02-10 11:11:17 -050073 err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
Liz Kammer8d62a4f2021-04-08 09:47:28 -040074 if err != nil {
75 t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
76 }
Yu Liue4312402023-01-18 09:15:31 -080077 verifyCqueryResult(t, bazelContext, label_foo, cfg_foo, "out/foo/foo.txt")
78 verifyCqueryResult(t, bazelContext, label_bar, cfg_bar, "out/foo/bar.txt")
79}
80
81func verifyCqueryResult(t *testing.T, ctx *mixedBuildBazelContext, label string, cfg configKey, result string) {
82 g, err := ctx.GetOutputFiles(label, cfg)
Chris Parsonsf874e462022-05-10 13:50:12 -040083 if err != nil {
84 t.Errorf("Expected cquery results after running InvokeBazel(), but got err %v", err)
Yu Liue4312402023-01-18 09:15:31 -080085 } else if w := []string{result}; !reflect.DeepEqual(w, g) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -040086 t.Errorf("Expected output %s, got %s", w, g)
87 }
88}
89
90func TestInvokeBazelWritesBazelFiles(t *testing.T) {
91 bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
Liz Kammer690fbac2023-02-10 11:11:17 -050092 err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
Liz Kammer8d62a4f2021-04-08 09:47:28 -040093 if err != nil {
94 t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
95 }
Lukacs T. Berki3069dd92021-05-11 16:54:29 +020096 if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "mixed_builds", "main.bzl")); os.IsNotExist(err) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -040097 t.Errorf("Expected main.bzl to exist, but it does not")
98 } else if err != nil {
99 t.Errorf("Unexpected error stating main.bzl %s", err)
100 }
101
Lukacs T. Berki3069dd92021-05-11 16:54:29 +0200102 if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "mixed_builds", "BUILD.bazel")); os.IsNotExist(err) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400103 t.Errorf("Expected BUILD.bazel to exist, but it does not")
104 } else if err != nil {
105 t.Errorf("Unexpected error stating BUILD.bazel %s", err)
106 }
107
Liz Kammer286c9fa2021-04-21 08:46:34 -0400108 if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "WORKSPACE.bazel")); os.IsNotExist(err) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400109 t.Errorf("Expected WORKSPACE.bazel to exist, but it does not")
110 } else if err != nil {
111 t.Errorf("Unexpected error stating WORKSPACE.bazel %s", err)
112 }
113}
114
115func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400116 type testCase struct {
117 input string
118 command string
119 }
120
121 var testCases = []testCase{
122 {`
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400123{
Jason Wu118fd2b2022-10-27 18:41:15 +0000124 "artifacts": [
125 { "id": 1, "path_fragment_id": 1 },
126 { "id": 2, "path_fragment_id": 2 }],
127 "actions": [{
128 "target_Id": 1,
129 "action_Key": "x",
130 "mnemonic": "x",
131 "arguments": ["touch", "foo"],
132 "input_dep_set_ids": [1],
133 "output_Ids": [1],
134 "primary_output_id": 1
135 }],
136 "dep_set_of_files": [
137 { "id": 1, "direct_artifact_ids": [1, 2] }],
138 "path_fragments": [
139 { "id": 1, "label": "one" },
140 { "id": 2, "label": "two" }]
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400141}`,
Jingwen Chenf3b1ec32022-11-07 15:02:48 +0000142 "cd 'test/exec_root' && rm -rf 'one' && touch foo",
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400143 }, {`
144{
Jason Wu118fd2b2022-10-27 18:41:15 +0000145 "artifacts": [
146 { "id": 1, "path_fragment_id": 10 },
147 { "id": 2, "path_fragment_id": 20 }],
148 "actions": [{
149 "target_Id": 100,
150 "action_Key": "x",
151 "mnemonic": "x",
152 "arguments": ["bogus", "command"],
153 "output_Ids": [1, 2],
154 "primary_output_id": 1
155 }],
156 "path_fragments": [
157 { "id": 10, "label": "one", "parent_id": 30 },
158 { "id": 20, "label": "one.d", "parent_id": 30 },
159 { "id": 30, "label": "parent" }]
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400160}`,
Jingwen Chenf3b1ec32022-11-07 15:02:48 +0000161 `cd 'test/exec_root' && rm -rf 'parent/one' && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1test/bazel_out/@g' 'parent/one.d'`,
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400162 },
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400163 }
164
Usta Shresthaef922252022-06-02 14:23:02 -0400165 for i, testCase := range testCases {
Jason Wu118fd2b2022-10-27 18:41:15 +0000166 data, err := JsonToActionGraphContainer(testCase.input)
167 if err != nil {
168 t.Error(err)
169 }
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000170 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{aqueryCmd: string(data)})
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400171
Liz Kammer690fbac2023-02-10 11:11:17 -0500172 err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400173 if err != nil {
Usta Shresthaef922252022-06-02 14:23:02 -0400174 t.Fatalf("testCase #%d: did not expect error invoking Bazel, but got %s", i+1, err)
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400175 }
176
177 got := bazelContext.BuildStatementsToRegister()
178 if want := 1; len(got) != want {
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700179 t.Fatalf("expected %d registered build statements, but got %#v", want, got)
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400180 }
181
182 cmd := RuleBuilderCommand{}
Colin Crossd5c7ddb2022-12-06 16:27:17 -0800183 ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
184 createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx)
Usta Shresthaef922252022-06-02 14:23:02 -0400185 if actual, expected := cmd.buf.String(), testCase.command; expected != actual {
186 t.Errorf("expected: [%s], actual: [%s]", expected, actual)
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400187 }
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400188 }
189}
190
Yu Liu8d82ac52022-05-17 15:13:28 -0700191func TestCoverageFlagsAfterInvokeBazel(t *testing.T) {
192 testConfig.productVariables.ClangCoverage = boolPtr(true)
193
194 testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
195 testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000196 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,+foo2,-bar1,-bar2")
Yu Liu8d82ac52022-05-17 15:13:28 -0700197
198 testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
199 testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000200 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,-bar1")
Yu Liu8d82ac52022-05-17 15:13:28 -0700201
202 testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
203 testConfig.productVariables.NativeCoverageExcludePaths = nil
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000204 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1")
Yu Liu8d82ac52022-05-17 15:13:28 -0700205
206 testConfig.productVariables.NativeCoveragePaths = nil
207 testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000208 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=-bar1")
Yu Liu8d82ac52022-05-17 15:13:28 -0700209
Wei Licbd181c2022-11-16 08:59:23 -0800210 testConfig.productVariables.NativeCoveragePaths = []string{"*"}
211 testConfig.productVariables.NativeCoverageExcludePaths = nil
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000212 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+.*")
Wei Licbd181c2022-11-16 08:59:23 -0800213
Yu Liu8d82ac52022-05-17 15:13:28 -0700214 testConfig.productVariables.ClangCoverage = boolPtr(false)
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000215 verifyAqueryDoesNotContainSubstrings(t, testConfig, "collect_code_coverage", "instrumentation_filter")
Yu Liu8d82ac52022-05-17 15:13:28 -0700216}
217
Chris Parsons3a8d0fb2023-02-02 18:16:29 -0500218func TestBazelRequestsSorted(t *testing.T) {
219 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
220
Yu Liue4312402023-01-18 09:15:31 -0800221 cfgKeyArm64Android := configKey{arch: "arm64_armv8-a", osType: Android}
222 cfgKeyArm64Linux := configKey{arch: "arm64_armv8-a", osType: Linux}
223 cfgKeyOtherAndroid := configKey{arch: "otherarch", osType: Android}
224
225 bazelContext.QueueBazelRequest("zzz", cquery.GetOutputFiles, cfgKeyArm64Android)
226 bazelContext.QueueBazelRequest("ccc", cquery.GetApexInfo, cfgKeyArm64Android)
227 bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
228 bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
229 bazelContext.QueueBazelRequest("xxx", cquery.GetOutputFiles, cfgKeyArm64Linux)
230 bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyArm64Android)
231 bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyOtherAndroid)
232 bazelContext.QueueBazelRequest("bbb", cquery.GetOutputFiles, cfgKeyOtherAndroid)
Chris Parsons3a8d0fb2023-02-02 18:16:29 -0500233
234 if len(bazelContext.requests) != 7 {
235 t.Error("Expected 7 request elements, but got", len(bazelContext.requests))
236 }
237
238 lastString := ""
239 for _, val := range bazelContext.requests {
240 thisString := val.String()
241 if thisString <= lastString {
242 t.Errorf("Requests are not ordered correctly. '%s' came before '%s'", lastString, thisString)
243 }
244 lastString = thisString
245 }
246}
247
Yu Liue4312402023-01-18 09:15:31 -0800248func TestIsModuleNameAllowed(t *testing.T) {
249 libDisabled := "lib_disabled"
250 libEnabled := "lib_enabled"
251 libDclaWithinApex := "lib_dcla_within_apex"
252 libDclaNonApex := "lib_dcla_non_apex"
253 libNotConverted := "lib_not_converted"
254
255 disabledModules := map[string]bool{
256 libDisabled: true,
257 }
258 enabledModules := map[string]bool{
259 libEnabled: true,
260 }
261 dclaEnabledModules := map[string]bool{
262 libDclaWithinApex: true,
263 libDclaNonApex: true,
264 }
265
266 bazelContext := &mixedBuildBazelContext{
Yu Liue4312402023-01-18 09:15:31 -0800267 bazelEnabledModules: enabledModules,
268 bazelDisabledModules: disabledModules,
269 bazelDclaEnabledModules: dclaEnabledModules,
270 }
271
272 if bazelContext.IsModuleNameAllowed(libDisabled, true) {
273 t.Fatalf("%s shouldn't be allowed for mixed build", libDisabled)
274 }
275
276 if !bazelContext.IsModuleNameAllowed(libEnabled, true) {
277 t.Fatalf("%s should be allowed for mixed build", libEnabled)
278 }
279
280 if !bazelContext.IsModuleNameAllowed(libDclaWithinApex, true) {
281 t.Fatalf("%s should be allowed for mixed build", libDclaWithinApex)
282 }
283
284 if bazelContext.IsModuleNameAllowed(libDclaNonApex, false) {
285 t.Fatalf("%s shouldn't be allowed for mixed build", libDclaNonApex)
286 }
287
288 if bazelContext.IsModuleNameAllowed(libNotConverted, true) {
289 t.Fatalf("%s shouldn't be allowed for mixed build", libNotConverted)
290 }
291}
292
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000293func verifyAqueryContainsFlags(t *testing.T, config Config, expected ...string) {
294 t.Helper()
Yu Liu8d82ac52022-05-17 15:13:28 -0700295 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
296
Liz Kammer690fbac2023-02-10 11:11:17 -0500297 err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
Yu Liu8d82ac52022-05-17 15:13:28 -0700298 if err != nil {
299 t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
300 }
301
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000302 sliceContains := func(slice []string, x string) bool {
303 for _, s := range slice {
304 if s == x {
305 return true
306 }
307 }
308 return false
Yu Liu8d82ac52022-05-17 15:13:28 -0700309 }
310
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000311 aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
312
313 for _, expectedFlag := range expected {
314 if !sliceContains(aqueryArgv, expectedFlag) {
315 t.Errorf("aquery does not contain expected flag %#v. Argv was: %#v", expectedFlag, aqueryArgv)
316 }
317 }
318}
319
320func verifyAqueryDoesNotContainSubstrings(t *testing.T, config Config, substrings ...string) {
321 t.Helper()
322 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
323
324 err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
325 if err != nil {
326 t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
Yu Liu8d82ac52022-05-17 15:13:28 -0700327 }
328
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000329 sliceContainsSubstring := func(slice []string, substring string) bool {
330 for _, s := range slice {
331 if strings.Contains(s, substring) {
332 return true
333 }
334 }
335 return false
336 }
337
338 aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
339
340 for _, substring := range substrings {
341 if sliceContainsSubstring(aqueryArgv, substring) {
342 t.Errorf("aquery contains unexpected substring %#v. Argv was: %#v", substring, aqueryArgv)
343 }
344 }
Yu Liu8d82ac52022-05-17 15:13:28 -0700345}
346
Sasha Smundak39a301c2022-12-29 17:11:49 -0800347func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*mixedBuildBazelContext, string) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400348 t.Helper()
349 p := bazelPaths{
Lukacs T. Berki9f6c24a2021-08-26 15:07:24 +0200350 soongOutDir: t.TempDir(),
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400351 outputBase: "outputbase",
352 workspaceDir: "workspace_dir",
353 }
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000354 if _, exists := bazelCommandResults[aqueryCmd]; !exists {
355 bazelCommandResults[aqueryCmd] = ""
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400356 }
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000357 runner := &mockBazelRunner{
358 testHelper: t,
359 bazelCommandResults: bazelCommandResults,
360 bazelCommandRequests: map[bazelCommand]bazel.CmdRequest{},
361 }
Sasha Smundak39a301c2022-12-29 17:11:49 -0800362 return &mixedBuildBazelContext{
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400363 bazelRunner: runner,
364 paths: &p,
Lukacs T. Berki9f6c24a2021-08-26 15:07:24 +0200365 }, p.soongOutDir
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400366}
Jason Wu118fd2b2022-10-27 18:41:15 +0000367
368// Transform the json format to ActionGraphContainer
369func JsonToActionGraphContainer(inputString string) ([]byte, error) {
370 var aqueryProtoResult analysis_v2_proto.ActionGraphContainer
371 err := json.Unmarshal([]byte(inputString), &aqueryProtoResult)
372 if err != nil {
373 return []byte(""), err
374 }
375 data, _ := proto.Marshal(&aqueryProtoResult)
376 return data, err
377}