blob: a81a878d0871734a9c342eff6df20aa525f53b6a [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{
Yu Liue4312402023-01-18 09:15:31 -0800266 bazelEnabledModules: enabledModules,
267 bazelDisabledModules: disabledModules,
268 bazelDclaEnabledModules: dclaEnabledModules,
269 }
270
271 if bazelContext.IsModuleNameAllowed(libDisabled, true) {
272 t.Fatalf("%s shouldn't be allowed for mixed build", libDisabled)
273 }
274
275 if !bazelContext.IsModuleNameAllowed(libEnabled, true) {
276 t.Fatalf("%s should be allowed for mixed build", libEnabled)
277 }
278
279 if !bazelContext.IsModuleNameAllowed(libDclaWithinApex, true) {
280 t.Fatalf("%s should be allowed for mixed build", libDclaWithinApex)
281 }
282
283 if bazelContext.IsModuleNameAllowed(libDclaNonApex, false) {
284 t.Fatalf("%s shouldn't be allowed for mixed build", libDclaNonApex)
285 }
286
287 if bazelContext.IsModuleNameAllowed(libNotConverted, true) {
288 t.Fatalf("%s shouldn't be allowed for mixed build", libNotConverted)
289 }
290}
291
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000292func verifyAqueryContainsFlags(t *testing.T, config Config, expected ...string) {
293 t.Helper()
Yu Liu8d82ac52022-05-17 15:13:28 -0700294 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
295
Liz Kammer690fbac2023-02-10 11:11:17 -0500296 err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
Yu Liu8d82ac52022-05-17 15:13:28 -0700297 if err != nil {
298 t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
299 }
300
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000301 sliceContains := func(slice []string, x string) bool {
302 for _, s := range slice {
303 if s == x {
304 return true
305 }
306 }
307 return false
Yu Liu8d82ac52022-05-17 15:13:28 -0700308 }
309
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000310 aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
311
312 for _, expectedFlag := range expected {
313 if !sliceContains(aqueryArgv, expectedFlag) {
314 t.Errorf("aquery does not contain expected flag %#v. Argv was: %#v", expectedFlag, aqueryArgv)
315 }
316 }
317}
318
319func verifyAqueryDoesNotContainSubstrings(t *testing.T, config Config, substrings ...string) {
320 t.Helper()
321 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
322
323 err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
324 if err != nil {
325 t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
Yu Liu8d82ac52022-05-17 15:13:28 -0700326 }
327
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000328 sliceContainsSubstring := func(slice []string, substring string) bool {
329 for _, s := range slice {
330 if strings.Contains(s, substring) {
331 return true
332 }
333 }
334 return false
335 }
336
337 aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
338
339 for _, substring := range substrings {
340 if sliceContainsSubstring(aqueryArgv, substring) {
341 t.Errorf("aquery contains unexpected substring %#v. Argv was: %#v", substring, aqueryArgv)
342 }
343 }
Yu Liu8d82ac52022-05-17 15:13:28 -0700344}
345
Sasha Smundak39a301c2022-12-29 17:11:49 -0800346func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*mixedBuildBazelContext, string) {
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400347 t.Helper()
348 p := bazelPaths{
Lukacs T. Berki9f6c24a2021-08-26 15:07:24 +0200349 soongOutDir: t.TempDir(),
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400350 outputBase: "outputbase",
351 workspaceDir: "workspace_dir",
352 }
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000353 if _, exists := bazelCommandResults[aqueryCmd]; !exists {
354 bazelCommandResults[aqueryCmd] = ""
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400355 }
Chris Parsonsc9089dc2023-04-24 16:21:27 +0000356 runner := &mockBazelRunner{
357 testHelper: t,
358 bazelCommandResults: bazelCommandResults,
359 bazelCommandRequests: map[bazelCommand]bazel.CmdRequest{},
360 }
Sasha Smundak39a301c2022-12-29 17:11:49 -0800361 return &mixedBuildBazelContext{
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400362 bazelRunner: runner,
363 paths: &p,
Lukacs T. Berki9f6c24a2021-08-26 15:07:24 +0200364 }, p.soongOutDir
Liz Kammer8d62a4f2021-04-08 09:47:28 -0400365}
Jason Wu118fd2b2022-10-27 18:41:15 +0000366
367// Transform the json format to ActionGraphContainer
368func JsonToActionGraphContainer(inputString string) ([]byte, error) {
369 var aqueryProtoResult analysis_v2_proto.ActionGraphContainer
370 err := json.Unmarshal([]byte(inputString), &aqueryProtoResult)
371 if err != nil {
372 return []byte(""), err
373 }
374 data, _ := proto.Marshal(&aqueryProtoResult)
375 return data, err
376}