blob: b17b7652baaeb2d80a1d8a1d2e3f0c4ba3002076 [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",
61 }
62 cfg_foo := configKey{"arm64_armv8-a", Android, apexKey}
63 cfg_bar := configKey{arch: "arm64_armv8-a", osType: Android}
64 cmd_results := []string{
65 `@//foo:foo|arm64_armv8-a|android|within_apex|29>>out/foo/foo.txt`,
66 `@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
67 }
Chris Parsonsc9089dc2023-04-24 16:21:27 +000068 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{cqueryCmd: strings.Join(cmd_results, "\n")})
Yu Liue4312402023-01-18 09:15:31 -080069
70 bazelContext.QueueBazelRequest(label_foo, cquery.GetOutputFiles, cfg_foo)
71 bazelContext.QueueBazelRequest(label_bar, cquery.GetOutputFiles, cfg_bar)
Liz Kammer690fbac2023-02-10 11:11:17 -050072 err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
Liz Kammer8d62a4f2021-04-08 09:47:28 -040073 if err != nil {
74 t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
75 }
Yu Liue4312402023-01-18 09:15:31 -080076 verifyCqueryResult(t, bazelContext, label_foo, cfg_foo, "out/foo/foo.txt")
77 verifyCqueryResult(t, bazelContext, label_bar, cfg_bar, "out/foo/bar.txt")
78}
79
80func verifyCqueryResult(t *testing.T, ctx *mixedBuildBazelContext, label string, cfg configKey, result string) {
81 g, err := ctx.GetOutputFiles(label, cfg)
Chris Parsonsf874e462022-05-10 13:50:12 -040082 if err != nil {
83 t.Errorf("Expected cquery results after running InvokeBazel(), but got err %v", err)
Yu Liue4312402023-01-18 09:15:31 -080084 } else if w := []string{result}; !reflect.DeepEqual(w, g) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -040085 t.Errorf("Expected output %s, got %s", w, g)
86 }
87}
88
89func TestInvokeBazelWritesBazelFiles(t *testing.T) {
90 bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
Liz Kammer690fbac2023-02-10 11:11:17 -050091 err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
Liz Kammer8d62a4f2021-04-08 09:47:28 -040092 if err != nil {
93 t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
94 }
Lukacs T. Berki3069dd92021-05-11 16:54:29 +020095 if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "mixed_builds", "main.bzl")); os.IsNotExist(err) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -040096 t.Errorf("Expected main.bzl to exist, but it does not")
97 } else if err != nil {
98 t.Errorf("Unexpected error stating main.bzl %s", err)
99 }
100
Lukacs T. Berki3069dd92021-05-11 16:54:29 +0200101 if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "mixed_builds", "BUILD.bazel")); os.IsNotExist(err) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400102 t.Errorf("Expected BUILD.bazel to exist, but it does not")
103 } else if err != nil {
104 t.Errorf("Unexpected error stating BUILD.bazel %s", err)
105 }
106
Liz Kammer286c9fa2021-04-21 08:46:34 -0400107 if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "WORKSPACE.bazel")); os.IsNotExist(err) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400108 t.Errorf("Expected WORKSPACE.bazel to exist, but it does not")
109 } else if err != nil {
110 t.Errorf("Unexpected error stating WORKSPACE.bazel %s", err)
111 }
112}
113
114func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400115 type testCase struct {
116 input string
117 command string
118 }
119
120 var testCases = []testCase{
121 {`
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400122{
Jason Wu118fd2b2022-10-27 18:41:15 +0000123 "artifacts": [
124 { "id": 1, "path_fragment_id": 1 },
125 { "id": 2, "path_fragment_id": 2 }],
126 "actions": [{
127 "target_Id": 1,
128 "action_Key": "x",
129 "mnemonic": "x",
130 "arguments": ["touch", "foo"],
131 "input_dep_set_ids": [1],
132 "output_Ids": [1],
133 "primary_output_id": 1
134 }],
135 "dep_set_of_files": [
136 { "id": 1, "direct_artifact_ids": [1, 2] }],
137 "path_fragments": [
138 { "id": 1, "label": "one" },
139 { "id": 2, "label": "two" }]
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400140}`,
Jingwen Chenf3b1ec32022-11-07 15:02:48 +0000141 "cd 'test/exec_root' && rm -rf 'one' && touch foo",
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400142 }, {`
143{
Jason Wu118fd2b2022-10-27 18:41:15 +0000144 "artifacts": [
145 { "id": 1, "path_fragment_id": 10 },
146 { "id": 2, "path_fragment_id": 20 }],
147 "actions": [{
148 "target_Id": 100,
149 "action_Key": "x",
150 "mnemonic": "x",
151 "arguments": ["bogus", "command"],
152 "output_Ids": [1, 2],
153 "primary_output_id": 1
154 }],
155 "path_fragments": [
156 { "id": 10, "label": "one", "parent_id": 30 },
157 { "id": 20, "label": "one.d", "parent_id": 30 },
158 { "id": 30, "label": "parent" }]
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400159}`,
Jingwen Chenf3b1ec32022-11-07 15:02:48 +0000160 `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 -0400161 },
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400162 }
163
Usta Shresthaef922252022-06-02 14:23:02 -0400164 for i, testCase := range testCases {
Jason Wu118fd2b2022-10-27 18:41:15 +0000165 data, err := JsonToActionGraphContainer(testCase.input)
166 if err != nil {
167 t.Error(err)
168 }
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000169 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{aqueryCmd: string(data)})
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400170
Liz Kammer690fbac2023-02-10 11:11:17 -0500171 err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400172 if err != nil {
Usta Shresthaef922252022-06-02 14:23:02 -0400173 t.Fatalf("testCase #%d: did not expect error invoking Bazel, but got %s", i+1, err)
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400174 }
175
176 got := bazelContext.BuildStatementsToRegister()
177 if want := 1; len(got) != want {
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700178 t.Fatalf("expected %d registered build statements, but got %#v", want, got)
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400179 }
180
181 cmd := RuleBuilderCommand{}
Colin Crossd5c7ddb2022-12-06 16:27:17 -0800182 ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
183 createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx)
Usta Shresthaef922252022-06-02 14:23:02 -0400184 if actual, expected := cmd.buf.String(), testCase.command; expected != actual {
185 t.Errorf("expected: [%s], actual: [%s]", expected, actual)
Usta Shresthaacd5a0c2022-06-22 11:20:50 -0400186 }
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400187 }
188}
189
Yu Liu8d82ac52022-05-17 15:13:28 -0700190func TestCoverageFlagsAfterInvokeBazel(t *testing.T) {
191 testConfig.productVariables.ClangCoverage = boolPtr(true)
192
193 testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
194 testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000195 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,+foo2,-bar1,-bar2")
Yu Liu8d82ac52022-05-17 15:13:28 -0700196
197 testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
198 testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000199 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,-bar1")
Yu Liu8d82ac52022-05-17 15:13:28 -0700200
201 testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
202 testConfig.productVariables.NativeCoverageExcludePaths = nil
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000203 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1")
Yu Liu8d82ac52022-05-17 15:13:28 -0700204
205 testConfig.productVariables.NativeCoveragePaths = nil
206 testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000207 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=-bar1")
Yu Liu8d82ac52022-05-17 15:13:28 -0700208
Wei Licbd181c2022-11-16 08:59:23 -0800209 testConfig.productVariables.NativeCoveragePaths = []string{"*"}
210 testConfig.productVariables.NativeCoverageExcludePaths = nil
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000211 verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+.*")
Wei Licbd181c2022-11-16 08:59:23 -0800212
Yu Liu8d82ac52022-05-17 15:13:28 -0700213 testConfig.productVariables.ClangCoverage = boolPtr(false)
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000214 verifyAqueryDoesNotContainSubstrings(t, testConfig, "collect_code_coverage", "instrumentation_filter")
Yu Liu8d82ac52022-05-17 15:13:28 -0700215}
216
Chris Parsons3a8d0fb2023-02-02 18:16:29 -0500217func TestBazelRequestsSorted(t *testing.T) {
218 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
219
Yu Liue4312402023-01-18 09:15:31 -0800220 cfgKeyArm64Android := configKey{arch: "arm64_armv8-a", osType: Android}
221 cfgKeyArm64Linux := configKey{arch: "arm64_armv8-a", osType: Linux}
222 cfgKeyOtherAndroid := configKey{arch: "otherarch", osType: Android}
223
224 bazelContext.QueueBazelRequest("zzz", cquery.GetOutputFiles, cfgKeyArm64Android)
225 bazelContext.QueueBazelRequest("ccc", cquery.GetApexInfo, cfgKeyArm64Android)
226 bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
227 bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
228 bazelContext.QueueBazelRequest("xxx", cquery.GetOutputFiles, cfgKeyArm64Linux)
229 bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyArm64Android)
230 bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyOtherAndroid)
231 bazelContext.QueueBazelRequest("bbb", cquery.GetOutputFiles, cfgKeyOtherAndroid)
Chris Parsons3a8d0fb2023-02-02 18:16:29 -0500232
233 if len(bazelContext.requests) != 7 {
234 t.Error("Expected 7 request elements, but got", len(bazelContext.requests))
235 }
236
237 lastString := ""
238 for _, val := range bazelContext.requests {
239 thisString := val.String()
240 if thisString <= lastString {
241 t.Errorf("Requests are not ordered correctly. '%s' came before '%s'", lastString, thisString)
242 }
243 lastString = thisString
244 }
245}
246
Yu Liue4312402023-01-18 09:15:31 -0800247func TestIsModuleNameAllowed(t *testing.T) {
248 libDisabled := "lib_disabled"
249 libEnabled := "lib_enabled"
250 libDclaWithinApex := "lib_dcla_within_apex"
251 libDclaNonApex := "lib_dcla_non_apex"
252 libNotConverted := "lib_not_converted"
253
254 disabledModules := map[string]bool{
255 libDisabled: true,
256 }
257 enabledModules := map[string]bool{
258 libEnabled: true,
259 }
260 dclaEnabledModules := map[string]bool{
261 libDclaWithinApex: true,
262 libDclaNonApex: true,
263 }
264
265 bazelContext := &mixedBuildBazelContext{
266 modulesDefaultToBazel: false,
267 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}