blob: 940d85c5530045037552f73c1c5e2e242278b708 [file] [log] [blame]
Dan Willemsen9b587492017-07-10 22:13:00 -07001// Copyright 2017 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 build
16
17import (
18 "bytes"
19 "context"
Patrice Arruda13848222019-04-22 17:12:02 -070020 "fmt"
21 "io/ioutil"
22 "os"
23 "path/filepath"
Dan Willemsen9b587492017-07-10 22:13:00 -070024 "reflect"
25 "strings"
26 "testing"
27
28 "android/soong/ui/logger"
Liz Kammerca9cb2e2021-07-14 15:29:57 -040029 smpb "android/soong/ui/metrics/metrics_proto"
Patrice Arruda219eef32020-06-01 17:29:30 +000030 "android/soong/ui/status"
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -040031
Chris Parsonsef615e52022-08-18 22:04:11 -040032 "google.golang.org/protobuf/encoding/prototext"
Liz Kammerca9cb2e2021-07-14 15:29:57 -040033
Dan Willemsen4591b642021-05-24 14:24:12 -070034 "google.golang.org/protobuf/proto"
Dan Willemsen9b587492017-07-10 22:13:00 -070035)
36
37func testContext() Context {
38 return Context{&ContextImpl{
Dan Willemsenb82471a2018-05-17 16:37:09 -070039 Context: context.Background(),
40 Logger: logger.New(&bytes.Buffer{}),
Colin Cross097ed2a2019-06-08 21:48:58 -070041 Writer: &bytes.Buffer{},
Patrice Arruda219eef32020-06-01 17:29:30 +000042 Status: &status.Status{},
Dan Willemsen9b587492017-07-10 22:13:00 -070043 }}
44}
45
46func TestConfigParseArgsJK(t *testing.T) {
47 ctx := testContext()
48
49 testCases := []struct {
50 args []string
51
52 parallel int
53 keepGoing int
54 remaining []string
55 }{
56 {nil, -1, -1, nil},
57
58 {[]string{"-j"}, -1, -1, nil},
59 {[]string{"-j1"}, 1, -1, nil},
60 {[]string{"-j1234"}, 1234, -1, nil},
61
62 {[]string{"-j", "1"}, 1, -1, nil},
63 {[]string{"-j", "1234"}, 1234, -1, nil},
64 {[]string{"-j", "1234", "abc"}, 1234, -1, []string{"abc"}},
65 {[]string{"-j", "abc"}, -1, -1, []string{"abc"}},
66 {[]string{"-j", "1abc"}, -1, -1, []string{"1abc"}},
67
68 {[]string{"-k"}, -1, 0, nil},
69 {[]string{"-k0"}, -1, 0, nil},
70 {[]string{"-k1"}, -1, 1, nil},
71 {[]string{"-k1234"}, -1, 1234, nil},
72
73 {[]string{"-k", "0"}, -1, 0, nil},
74 {[]string{"-k", "1"}, -1, 1, nil},
75 {[]string{"-k", "1234"}, -1, 1234, nil},
76 {[]string{"-k", "1234", "abc"}, -1, 1234, []string{"abc"}},
77 {[]string{"-k", "abc"}, -1, 0, []string{"abc"}},
78 {[]string{"-k", "1abc"}, -1, 0, []string{"1abc"}},
79
80 // TODO: These are supported in Make, should we support them?
81 //{[]string{"-kj"}, -1, 0},
82 //{[]string{"-kj8"}, 8, 0},
83
84 // -jk is not valid in Make
85 }
86
87 for _, tc := range testCases {
88 t.Run(strings.Join(tc.args, " "), func(t *testing.T) {
89 defer logger.Recover(func(err error) {
90 t.Fatal(err)
91 })
92
Chris Parsonsb6e96902022-10-31 20:08:45 -040093 env := Environment([]string{})
Dan Willemsen9b587492017-07-10 22:13:00 -070094 c := &configImpl{
Chris Parsonsb6e96902022-10-31 20:08:45 -040095 environ: &env,
Dan Willemsen9b587492017-07-10 22:13:00 -070096 parallel: -1,
97 keepGoing: -1,
98 }
99 c.parseArgs(ctx, tc.args)
100
101 if c.parallel != tc.parallel {
102 t.Errorf("for %q, parallel:\nwant: %d\n got: %d\n",
103 strings.Join(tc.args, " "),
104 tc.parallel, c.parallel)
105 }
106 if c.keepGoing != tc.keepGoing {
107 t.Errorf("for %q, keep going:\nwant: %d\n got: %d\n",
108 strings.Join(tc.args, " "),
109 tc.keepGoing, c.keepGoing)
110 }
111 if !reflect.DeepEqual(c.arguments, tc.remaining) {
112 t.Errorf("for %q, remaining arguments:\nwant: %q\n got: %q\n",
113 strings.Join(tc.args, " "),
114 tc.remaining, c.arguments)
115 }
116 })
117 }
118}
Dan Willemsen091525e2017-07-11 14:17:50 -0700119
120func TestConfigParseArgsVars(t *testing.T) {
121 ctx := testContext()
122
123 testCases := []struct {
124 env []string
125 args []string
126
127 expectedEnv []string
128 remaining []string
129 }{
130 {},
131 {
132 env: []string{"A=bc"},
133
134 expectedEnv: []string{"A=bc"},
135 },
136 {
137 args: []string{"abc"},
138
139 remaining: []string{"abc"},
140 },
141
142 {
143 args: []string{"A=bc"},
144
145 expectedEnv: []string{"A=bc"},
146 },
147 {
148 env: []string{"A=a"},
149 args: []string{"A=bc"},
150
151 expectedEnv: []string{"A=bc"},
152 },
153
154 {
155 env: []string{"A=a"},
156 args: []string{"A=", "=b"},
157
158 expectedEnv: []string{"A="},
159 remaining: []string{"=b"},
160 },
161 }
162
163 for _, tc := range testCases {
164 t.Run(strings.Join(tc.args, " "), func(t *testing.T) {
165 defer logger.Recover(func(err error) {
166 t.Fatal(err)
167 })
168
169 e := Environment(tc.env)
170 c := &configImpl{
171 environ: &e,
172 }
173 c.parseArgs(ctx, tc.args)
174
175 if !reflect.DeepEqual([]string(*c.environ), tc.expectedEnv) {
176 t.Errorf("for env=%q args=%q, environment:\nwant: %q\n got: %q\n",
177 tc.env, tc.args,
178 tc.expectedEnv, []string(*c.environ))
179 }
180 if !reflect.DeepEqual(c.arguments, tc.remaining) {
181 t.Errorf("for env=%q args=%q, remaining arguments:\nwant: %q\n got: %q\n",
182 tc.env, tc.args,
183 tc.remaining, c.arguments)
184 }
185 })
186 }
187}
Patrice Arruda13848222019-04-22 17:12:02 -0700188
189func TestConfigCheckTopDir(t *testing.T) {
190 ctx := testContext()
191 buildRootDir := filepath.Dir(srcDirFileCheck)
192 expectedErrStr := fmt.Sprintf("Current working directory must be the source tree. %q not found.", srcDirFileCheck)
193
194 tests := []struct {
195 // ********* Setup *********
196 // Test description.
197 description string
198
199 // ********* Action *********
200 // If set to true, the build root file is created.
201 rootBuildFile bool
202
203 // The current path where Soong is being executed.
204 path string
205
206 // ********* Validation *********
207 // Expecting error and validate the error string against expectedErrStr.
208 wantErr bool
209 }{{
210 description: "current directory is the root source tree",
211 rootBuildFile: true,
212 path: ".",
213 wantErr: false,
214 }, {
215 description: "one level deep in the source tree",
216 rootBuildFile: true,
217 path: "1",
218 wantErr: true,
219 }, {
220 description: "very deep in the source tree",
221 rootBuildFile: true,
222 path: "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7",
223 wantErr: true,
224 }, {
225 description: "outside of source tree",
226 rootBuildFile: false,
227 path: "1/2/3/4/5",
228 wantErr: true,
229 }}
230
231 for _, tt := range tests {
232 t.Run(tt.description, func(t *testing.T) {
233 defer logger.Recover(func(err error) {
234 if !tt.wantErr {
235 t.Fatalf("Got unexpected error: %v", err)
236 }
237 if expectedErrStr != err.Error() {
238 t.Fatalf("expected %s, got %s", expectedErrStr, err.Error())
239 }
240 })
241
242 // Create the root source tree.
243 rootDir, err := ioutil.TempDir("", "")
244 if err != nil {
245 t.Fatal(err)
246 }
247 defer os.RemoveAll(rootDir)
248
249 // Create the build root file. This is to test if topDir returns an error if the build root
250 // file does not exist.
251 if tt.rootBuildFile {
252 dir := filepath.Join(rootDir, buildRootDir)
253 if err := os.MkdirAll(dir, 0755); err != nil {
254 t.Errorf("failed to create %s directory: %v", dir, err)
255 }
256 f := filepath.Join(rootDir, srcDirFileCheck)
257 if err := ioutil.WriteFile(f, []byte{}, 0644); err != nil {
258 t.Errorf("failed to create file %s: %v", f, err)
259 }
260 }
261
262 // Next block of code is to set the current directory.
263 dir := rootDir
264 if tt.path != "" {
265 dir = filepath.Join(dir, tt.path)
266 if err := os.MkdirAll(dir, 0755); err != nil {
267 t.Errorf("failed to create %s directory: %v", dir, err)
268 }
269 }
270 curDir, err := os.Getwd()
271 if err != nil {
272 t.Fatalf("failed to get the current directory: %v", err)
273 }
274 defer func() { os.Chdir(curDir) }()
275
276 if err := os.Chdir(dir); err != nil {
277 t.Fatalf("failed to change directory to %s: %v", dir, err)
278 }
279
280 checkTopDir(ctx)
281 })
282 }
283}
284
285func TestConfigConvertToTarget(t *testing.T) {
286 tests := []struct {
287 // ********* Setup *********
288 // Test description.
289 description string
290
291 // ********* Action *********
292 // The current directory where Soong is being executed.
293 dir string
294
295 // The current prefix string to be pre-appended to the target.
296 prefix string
297
298 // ********* Validation *********
299 // The expected target to be invoked in ninja.
300 expectedTarget string
301 }{{
302 description: "one level directory in source tree",
303 dir: "test1",
304 prefix: "MODULES-IN-",
305 expectedTarget: "MODULES-IN-test1",
306 }, {
307 description: "multiple level directories in source tree",
308 dir: "test1/test2/test3/test4",
309 prefix: "GET-INSTALL-PATH-IN-",
310 expectedTarget: "GET-INSTALL-PATH-IN-test1-test2-test3-test4",
311 }}
312 for _, tt := range tests {
313 t.Run(tt.description, func(t *testing.T) {
314 target := convertToTarget(tt.dir, tt.prefix)
315 if target != tt.expectedTarget {
316 t.Errorf("expected %s, got %s for target", tt.expectedTarget, target)
317 }
318 })
319 }
320}
321
322func setTop(t *testing.T, dir string) func() {
323 curDir, err := os.Getwd()
324 if err != nil {
325 t.Fatalf("failed to get current directory: %v", err)
326 }
327 if err := os.Chdir(dir); err != nil {
328 t.Fatalf("failed to change directory to top dir %s: %v", dir, err)
329 }
330 return func() { os.Chdir(curDir) }
331}
332
333func createBuildFiles(t *testing.T, topDir string, buildFiles []string) {
334 for _, buildFile := range buildFiles {
335 buildFile = filepath.Join(topDir, buildFile)
336 if err := ioutil.WriteFile(buildFile, []byte{}, 0644); err != nil {
337 t.Errorf("failed to create file %s: %v", buildFile, err)
338 }
339 }
340}
341
342func createDirectories(t *testing.T, topDir string, dirs []string) {
343 for _, dir := range dirs {
344 dir = filepath.Join(topDir, dir)
345 if err := os.MkdirAll(dir, 0755); err != nil {
346 t.Errorf("failed to create %s directory: %v", dir, err)
347 }
348 }
349}
350
351func TestConfigGetTargets(t *testing.T) {
352 ctx := testContext()
353 tests := []struct {
354 // ********* Setup *********
355 // Test description.
356 description string
357
358 // Directories that exist in the source tree.
359 dirsInTrees []string
360
361 // Build files that exists in the source tree.
362 buildFiles []string
363
364 // ********* Action *********
365 // Directories passed in to soong_ui.
366 dirs []string
367
368 // Current directory that the user executed the build action command.
369 curDir string
370
371 // ********* Validation *********
372 // Expected targets from the function.
373 expectedTargets []string
374
Patrice Arruda13848222019-04-22 17:12:02 -0700375 // Expecting error from running test case.
376 errStr string
377 }{{
Dan Willemsence41e942019-07-29 23:39:30 -0700378 description: "one target dir specified",
379 dirsInTrees: []string{"0/1/2/3"},
380 buildFiles: []string{"0/1/2/3/Android.bp"},
381 dirs: []string{"1/2/3"},
382 curDir: "0",
383 expectedTargets: []string{"MODULES-IN-0-1-2-3"},
Patrice Arruda13848222019-04-22 17:12:02 -0700384 }, {
385 description: "one target dir specified, build file does not exist",
386 dirsInTrees: []string{"0/1/2/3"},
387 buildFiles: []string{},
388 dirs: []string{"1/2/3"},
389 curDir: "0",
390 errStr: "Build file not found for 0/1/2/3 directory",
391 }, {
392 description: "one target dir specified, invalid targets specified",
393 dirsInTrees: []string{"0/1/2/3"},
394 buildFiles: []string{},
395 dirs: []string{"1/2/3:t1:t2"},
396 curDir: "0",
397 errStr: "1/2/3:t1:t2 not in proper directory:target1,target2,... format (\":\" was specified more than once)",
398 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700399 description: "one target dir specified, no targets specified but has colon",
400 dirsInTrees: []string{"0/1/2/3"},
401 buildFiles: []string{"0/1/2/3/Android.bp"},
402 dirs: []string{"1/2/3:"},
403 curDir: "0",
404 expectedTargets: []string{"MODULES-IN-0-1-2-3"},
Patrice Arruda13848222019-04-22 17:12:02 -0700405 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700406 description: "one target dir specified, two targets specified",
407 dirsInTrees: []string{"0/1/2/3"},
408 buildFiles: []string{"0/1/2/3/Android.bp"},
409 dirs: []string{"1/2/3:t1,t2"},
410 curDir: "0",
411 expectedTargets: []string{"t1", "t2"},
Patrice Arruda13848222019-04-22 17:12:02 -0700412 }, {
413 description: "one target dir specified, no targets and has a comma",
414 dirsInTrees: []string{"0/1/2/3"},
415 buildFiles: []string{"0/1/2/3/Android.bp"},
416 dirs: []string{"1/2/3:,"},
417 curDir: "0",
418 errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
419 }, {
420 description: "one target dir specified, improper targets defined",
421 dirsInTrees: []string{"0/1/2/3"},
422 buildFiles: []string{"0/1/2/3/Android.bp"},
423 dirs: []string{"1/2/3:,t1"},
424 curDir: "0",
425 errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
426 }, {
427 description: "one target dir specified, blank target",
428 dirsInTrees: []string{"0/1/2/3"},
429 buildFiles: []string{"0/1/2/3/Android.bp"},
430 dirs: []string{"1/2/3:t1,"},
431 curDir: "0",
432 errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
433 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700434 description: "one target dir specified, many targets specified",
435 dirsInTrees: []string{"0/1/2/3"},
436 buildFiles: []string{"0/1/2/3/Android.bp"},
437 dirs: []string{"1/2/3:t1,t2,t3,t4,t5,t6,t7,t8,t9,t10"},
438 curDir: "0",
439 expectedTargets: []string{"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10"},
Patrice Arruda13848222019-04-22 17:12:02 -0700440 }, {
441 description: "one target dir specified, one target specified, build file does not exist",
442 dirsInTrees: []string{"0/1/2/3"},
443 buildFiles: []string{},
444 dirs: []string{"1/2/3:t1"},
445 curDir: "0",
Patrice Arruda9450d0b2019-07-08 11:06:46 -0700446 errStr: "Couldn't locate a build file from 0/1/2/3 directory",
Patrice Arruda13848222019-04-22 17:12:02 -0700447 }, {
448 description: "one target dir specified, one target specified, build file not in target dir",
449 dirsInTrees: []string{"0/1/2/3"},
450 buildFiles: []string{"0/1/2/Android.mk"},
451 dirs: []string{"1/2/3:t1"},
452 curDir: "0",
453 errStr: "Couldn't locate a build file from 0/1/2/3 directory",
454 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700455 description: "one target dir specified, build file not in target dir",
456 dirsInTrees: []string{"0/1/2/3"},
457 buildFiles: []string{"0/1/2/Android.mk"},
458 dirs: []string{"1/2/3"},
459 curDir: "0",
460 expectedTargets: []string{"MODULES-IN-0-1-2"},
Patrice Arruda13848222019-04-22 17:12:02 -0700461 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700462 description: "multiple targets dir specified, targets specified",
463 dirsInTrees: []string{"0/1/2/3", "0/3/4"},
464 buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
465 dirs: []string{"1/2/3:t1,t2", "3/4:t3,t4,t5"},
466 curDir: "0",
467 expectedTargets: []string{"t1", "t2", "t3", "t4", "t5"},
Patrice Arruda13848222019-04-22 17:12:02 -0700468 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700469 description: "multiple targets dir specified, one directory has targets specified",
470 dirsInTrees: []string{"0/1/2/3", "0/3/4"},
471 buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
472 dirs: []string{"1/2/3:t1,t2", "3/4"},
473 curDir: "0",
474 expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
Patrice Arruda13848222019-04-22 17:12:02 -0700475 }, {
476 description: "two dirs specified, only one dir exist",
477 dirsInTrees: []string{"0/1/2/3"},
478 buildFiles: []string{"0/1/2/3/Android.mk"},
479 dirs: []string{"1/2/3:t1", "3/4"},
480 curDir: "0",
481 errStr: "couldn't find directory 0/3/4",
482 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700483 description: "multiple targets dirs specified at root source tree",
484 dirsInTrees: []string{"0/1/2/3", "0/3/4"},
485 buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
486 dirs: []string{"0/1/2/3:t1,t2", "0/3/4"},
487 curDir: ".",
488 expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
Patrice Arruda13848222019-04-22 17:12:02 -0700489 }, {
490 description: "no directories specified",
491 dirsInTrees: []string{"0/1/2/3", "0/3/4"},
492 buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
493 dirs: []string{},
494 curDir: ".",
495 }}
496 for _, tt := range tests {
497 t.Run(tt.description, func(t *testing.T) {
498 defer logger.Recover(func(err error) {
499 if tt.errStr == "" {
500 t.Fatalf("Got unexpected error: %v", err)
501 }
502 if tt.errStr != err.Error() {
503 t.Errorf("expected %s, got %s", tt.errStr, err.Error())
504 }
505 })
506
507 // Create the root source tree.
508 topDir, err := ioutil.TempDir("", "")
509 if err != nil {
510 t.Fatalf("failed to create temp dir: %v", err)
511 }
512 defer os.RemoveAll(topDir)
513
514 createDirectories(t, topDir, tt.dirsInTrees)
515 createBuildFiles(t, topDir, tt.buildFiles)
516 r := setTop(t, topDir)
517 defer r()
518
Dan Willemsence41e942019-07-29 23:39:30 -0700519 targets := getTargetsFromDirs(ctx, tt.curDir, tt.dirs, "MODULES-IN-")
Patrice Arruda13848222019-04-22 17:12:02 -0700520 if !reflect.DeepEqual(targets, tt.expectedTargets) {
521 t.Errorf("expected %v, got %v for targets", tt.expectedTargets, targets)
522 }
Patrice Arruda13848222019-04-22 17:12:02 -0700523
524 // If the execution reached here and there was an expected error code, the unit test case failed.
525 if tt.errStr != "" {
526 t.Errorf("expecting error %s", tt.errStr)
527 }
528 })
529 }
530}
531
532func TestConfigFindBuildFile(t *testing.T) {
533 ctx := testContext()
534
535 tests := []struct {
536 // ********* Setup *********
537 // Test description.
538 description string
539
540 // Array of build files to create in dir.
541 buildFiles []string
542
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700543 // Directories that exist in the source tree.
544 dirsInTrees []string
545
Patrice Arruda13848222019-04-22 17:12:02 -0700546 // ********* Action *********
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700547 // The base directory is where findBuildFile is invoked.
Patrice Arruda13848222019-04-22 17:12:02 -0700548 dir string
549
550 // ********* Validation *********
551 // Expected build file path to find.
552 expectedBuildFile string
553 }{{
554 description: "build file exists at leaf directory",
555 buildFiles: []string{"1/2/3/Android.bp"},
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700556 dirsInTrees: []string{"1/2/3"},
Patrice Arruda13848222019-04-22 17:12:02 -0700557 dir: "1/2/3",
558 expectedBuildFile: "1/2/3/Android.mk",
559 }, {
560 description: "build file exists in all directory paths",
561 buildFiles: []string{"1/Android.mk", "1/2/Android.mk", "1/2/3/Android.mk"},
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700562 dirsInTrees: []string{"1/2/3"},
Patrice Arruda13848222019-04-22 17:12:02 -0700563 dir: "1/2/3",
564 expectedBuildFile: "1/2/3/Android.mk",
565 }, {
566 description: "build file does not exist in all directory paths",
567 buildFiles: []string{},
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700568 dirsInTrees: []string{"1/2/3"},
Patrice Arruda13848222019-04-22 17:12:02 -0700569 dir: "1/2/3",
570 expectedBuildFile: "",
571 }, {
572 description: "build file exists only at top directory",
573 buildFiles: []string{"Android.bp"},
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700574 dirsInTrees: []string{"1/2/3"},
Patrice Arruda13848222019-04-22 17:12:02 -0700575 dir: "1/2/3",
576 expectedBuildFile: "",
577 }, {
578 description: "build file exist in a subdirectory",
579 buildFiles: []string{"1/2/Android.bp"},
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700580 dirsInTrees: []string{"1/2/3"},
Patrice Arruda13848222019-04-22 17:12:02 -0700581 dir: "1/2/3",
582 expectedBuildFile: "1/2/Android.mk",
583 }, {
584 description: "build file exists in a subdirectory",
585 buildFiles: []string{"1/Android.mk"},
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700586 dirsInTrees: []string{"1/2/3"},
Patrice Arruda13848222019-04-22 17:12:02 -0700587 dir: "1/2/3",
588 expectedBuildFile: "1/Android.mk",
589 }, {
590 description: "top directory",
591 buildFiles: []string{"Android.bp"},
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700592 dirsInTrees: []string{},
Patrice Arruda13848222019-04-22 17:12:02 -0700593 dir: ".",
594 expectedBuildFile: "",
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700595 }, {
596 description: "build file exists in subdirectory",
597 buildFiles: []string{"1/2/3/Android.bp", "1/2/4/Android.bp"},
598 dirsInTrees: []string{"1/2/3", "1/2/4"},
599 dir: "1/2",
600 expectedBuildFile: "1/2/Android.mk",
601 }, {
602 description: "build file exists in parent subdirectory",
603 buildFiles: []string{"1/5/Android.bp"},
604 dirsInTrees: []string{"1/2/3", "1/2/4", "1/5"},
605 dir: "1/2",
606 expectedBuildFile: "1/Android.mk",
607 }, {
608 description: "build file exists in deep parent's subdirectory.",
609 buildFiles: []string{"1/5/6/Android.bp"},
610 dirsInTrees: []string{"1/2/3", "1/2/4", "1/5/6", "1/5/7"},
611 dir: "1/2",
612 expectedBuildFile: "1/Android.mk",
Patrice Arruda13848222019-04-22 17:12:02 -0700613 }}
614
615 for _, tt := range tests {
616 t.Run(tt.description, func(t *testing.T) {
617 defer logger.Recover(func(err error) {
618 t.Fatalf("Got unexpected error: %v", err)
619 })
620
621 topDir, err := ioutil.TempDir("", "")
622 if err != nil {
623 t.Fatalf("failed to create temp dir: %v", err)
624 }
625 defer os.RemoveAll(topDir)
626
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700627 createDirectories(t, topDir, tt.dirsInTrees)
Patrice Arruda13848222019-04-22 17:12:02 -0700628 createBuildFiles(t, topDir, tt.buildFiles)
629
630 curDir, err := os.Getwd()
631 if err != nil {
632 t.Fatalf("Could not get working directory: %v", err)
633 }
634 defer func() { os.Chdir(curDir) }()
635 if err := os.Chdir(topDir); err != nil {
636 t.Fatalf("Could not change top dir to %s: %v", topDir, err)
637 }
638
639 buildFile := findBuildFile(ctx, tt.dir)
640 if buildFile != tt.expectedBuildFile {
641 t.Errorf("expected %q, got %q for build file", tt.expectedBuildFile, buildFile)
642 }
643 })
644 }
645}
646
647func TestConfigSplitArgs(t *testing.T) {
648 tests := []struct {
649 // ********* Setup *********
650 // Test description.
651 description string
652
653 // ********* Action *********
654 // Arguments passed in to soong_ui.
655 args []string
656
657 // ********* Validation *********
658 // Expected newArgs list after extracting the directories.
659 expectedNewArgs []string
660
661 // Expected directories
662 expectedDirs []string
663 }{{
664 description: "flags but no directories specified",
665 args: []string{"showcommands", "-j", "-k"},
666 expectedNewArgs: []string{"showcommands", "-j", "-k"},
667 expectedDirs: []string{},
668 }, {
669 description: "flags and one directory specified",
670 args: []string{"snod", "-j", "dir:target1,target2"},
671 expectedNewArgs: []string{"snod", "-j"},
672 expectedDirs: []string{"dir:target1,target2"},
673 }, {
674 description: "flags and directories specified",
675 args: []string{"dist", "-k", "dir1", "dir2:target1,target2"},
676 expectedNewArgs: []string{"dist", "-k"},
677 expectedDirs: []string{"dir1", "dir2:target1,target2"},
678 }, {
679 description: "only directories specified",
680 args: []string{"dir1", "dir2", "dir3:target1,target2"},
681 expectedNewArgs: []string{},
682 expectedDirs: []string{"dir1", "dir2", "dir3:target1,target2"},
683 }}
684 for _, tt := range tests {
685 t.Run(tt.description, func(t *testing.T) {
686 args, dirs := splitArgs(tt.args)
687 if !reflect.DeepEqual(tt.expectedNewArgs, args) {
688 t.Errorf("expected %v, got %v for arguments", tt.expectedNewArgs, args)
689 }
690 if !reflect.DeepEqual(tt.expectedDirs, dirs) {
691 t.Errorf("expected %v, got %v for directories", tt.expectedDirs, dirs)
692 }
693 })
694 }
695}
696
697type envVar struct {
698 name string
699 value string
700}
701
702type buildActionTestCase struct {
703 // ********* Setup *********
704 // Test description.
705 description string
706
707 // Directories that exist in the source tree.
708 dirsInTrees []string
709
710 // Build files that exists in the source tree.
711 buildFiles []string
712
Patrice Arrudababa9a92019-07-03 10:47:34 -0700713 // Create root symlink that points to topDir.
714 rootSymlink bool
715
Patrice Arruda13848222019-04-22 17:12:02 -0700716 // ********* Action *********
717 // Arguments passed in to soong_ui.
718 args []string
719
720 // Directory where the build action was invoked.
721 curDir string
722
723 // WITH_TIDY_ONLY environment variable specified.
724 tidyOnly string
725
726 // ********* Validation *********
727 // Expected arguments to be in Config instance.
728 expectedArgs []string
729
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700730 // Expecting error from running test case.
731 expectedErrStr string
Patrice Arruda13848222019-04-22 17:12:02 -0700732}
733
Dan Willemsence41e942019-07-29 23:39:30 -0700734func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction) {
Patrice Arruda13848222019-04-22 17:12:02 -0700735 ctx := testContext()
736
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700737 defer logger.Recover(func(err error) {
738 if tt.expectedErrStr == "" {
739 t.Fatalf("Got unexpected error: %v", err)
740 }
741 if tt.expectedErrStr != err.Error() {
742 t.Errorf("expected %s, got %s", tt.expectedErrStr, err.Error())
743 }
744 })
745
Patrice Arruda13848222019-04-22 17:12:02 -0700746 // Environment variables to set it to blank on every test case run.
747 resetEnvVars := []string{
Patrice Arruda13848222019-04-22 17:12:02 -0700748 "WITH_TIDY_ONLY",
749 }
750
751 for _, name := range resetEnvVars {
752 if err := os.Unsetenv(name); err != nil {
753 t.Fatalf("failed to unset environment variable %s: %v", name, err)
754 }
755 }
756 if tt.tidyOnly != "" {
757 if err := os.Setenv("WITH_TIDY_ONLY", tt.tidyOnly); err != nil {
758 t.Errorf("failed to set WITH_TIDY_ONLY to %s: %v", tt.tidyOnly, err)
759 }
760 }
761
762 // Create the root source tree.
763 topDir, err := ioutil.TempDir("", "")
764 if err != nil {
765 t.Fatalf("failed to create temp dir: %v", err)
766 }
767 defer os.RemoveAll(topDir)
768
769 createDirectories(t, topDir, tt.dirsInTrees)
770 createBuildFiles(t, topDir, tt.buildFiles)
771
Patrice Arrudababa9a92019-07-03 10:47:34 -0700772 if tt.rootSymlink {
773 // Create a secondary root source tree which points to the true root source tree.
774 symlinkTopDir, err := ioutil.TempDir("", "")
775 if err != nil {
776 t.Fatalf("failed to create symlink temp dir: %v", err)
777 }
778 defer os.RemoveAll(symlinkTopDir)
779
780 symlinkTopDir = filepath.Join(symlinkTopDir, "root")
781 err = os.Symlink(topDir, symlinkTopDir)
782 if err != nil {
783 t.Fatalf("failed to create symlink: %v", err)
784 }
785 topDir = symlinkTopDir
786 }
787
Patrice Arruda13848222019-04-22 17:12:02 -0700788 r := setTop(t, topDir)
789 defer r()
790
791 // The next block is to create the root build file.
792 rootBuildFileDir := filepath.Dir(srcDirFileCheck)
793 if err := os.MkdirAll(rootBuildFileDir, 0755); err != nil {
794 t.Fatalf("Failed to create %s directory: %v", rootBuildFileDir, err)
795 }
796
797 if err := ioutil.WriteFile(srcDirFileCheck, []byte{}, 0644); err != nil {
798 t.Fatalf("failed to create %s file: %v", srcDirFileCheck, err)
799 }
800
Dan Willemsence41e942019-07-29 23:39:30 -0700801 args := getConfigArgs(action, tt.curDir, ctx, tt.args)
Patrice Arruda13848222019-04-22 17:12:02 -0700802 if !reflect.DeepEqual(tt.expectedArgs, args) {
803 t.Fatalf("expected %v, got %v for config arguments", tt.expectedArgs, args)
804 }
805
Patrice Arruda0dcf27f2019-07-08 17:03:33 -0700806 // If the execution reached here and there was an expected error code, the unit test case failed.
807 if tt.expectedErrStr != "" {
808 t.Errorf("expecting error %s", tt.expectedErrStr)
809 }
Patrice Arruda13848222019-04-22 17:12:02 -0700810}
811
Patrice Arruda39282062019-06-20 16:35:12 -0700812func TestGetConfigArgsBuildModules(t *testing.T) {
813 tests := []buildActionTestCase{{
Dan Willemsence41e942019-07-29 23:39:30 -0700814 description: "normal execution from the root source tree directory",
815 dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
816 buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "0/3/Android.mk"},
817 args: []string{"-j", "fake_module", "fake_module2"},
818 curDir: ".",
819 tidyOnly: "",
820 expectedArgs: []string{"-j", "fake_module", "fake_module2"},
Patrice Arruda39282062019-06-20 16:35:12 -0700821 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700822 description: "normal execution in deep directory",
823 dirsInTrees: []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
824 buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
825 args: []string{"-j", "fake_module", "fake_module2", "-k"},
826 curDir: "1/2/3/4/5/6/7/8/9",
827 tidyOnly: "",
828 expectedArgs: []string{"-j", "fake_module", "fake_module2", "-k"},
Patrice Arruda39282062019-06-20 16:35:12 -0700829 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700830 description: "normal execution in deep directory, no targets",
831 dirsInTrees: []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
832 buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
833 args: []string{"-j", "-k"},
834 curDir: "1/2/3/4/5/6/7/8/9",
835 tidyOnly: "",
836 expectedArgs: []string{"-j", "-k"},
Patrice Arruda39282062019-06-20 16:35:12 -0700837 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700838 description: "normal execution in root source tree, no args",
839 dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
840 buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp"},
841 args: []string{},
842 curDir: "0/2",
843 tidyOnly: "",
844 expectedArgs: []string{},
Patrice Arrudababa9a92019-07-03 10:47:34 -0700845 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700846 description: "normal execution in symlink root source tree, no args",
847 dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
848 buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp"},
849 rootSymlink: true,
850 args: []string{},
851 curDir: "0/2",
852 tidyOnly: "",
853 expectedArgs: []string{},
Patrice Arruda39282062019-06-20 16:35:12 -0700854 }}
855 for _, tt := range tests {
856 t.Run("build action BUILD_MODULES with dependencies, "+tt.description, func(t *testing.T) {
Dan Willemsence41e942019-07-29 23:39:30 -0700857 testGetConfigArgs(t, tt, BUILD_MODULES)
Patrice Arruda13848222019-04-22 17:12:02 -0700858 })
859 }
860}
861
862func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) {
863 tests := []buildActionTestCase{{
Dan Willemsence41e942019-07-29 23:39:30 -0700864 description: "normal execution in a directory",
865 dirsInTrees: []string{"0/1/2"},
866 buildFiles: []string{"0/1/2/Android.mk"},
867 args: []string{"fake-module"},
868 curDir: "0/1/2",
869 tidyOnly: "",
870 expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
Patrice Arruda13848222019-04-22 17:12:02 -0700871 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700872 description: "build file in parent directory",
873 dirsInTrees: []string{"0/1/2"},
874 buildFiles: []string{"0/1/Android.mk"},
875 args: []string{},
876 curDir: "0/1/2",
877 tidyOnly: "",
878 expectedArgs: []string{"MODULES-IN-0-1"},
Patrice Arruda13848222019-04-22 17:12:02 -0700879 },
880 {
Dan Willemsence41e942019-07-29 23:39:30 -0700881 description: "build file in parent directory, multiple module names passed in",
882 dirsInTrees: []string{"0/1/2"},
883 buildFiles: []string{"0/1/Android.mk"},
884 args: []string{"fake-module1", "fake-module2", "fake-module3"},
885 curDir: "0/1/2",
886 tidyOnly: "",
887 expectedArgs: []string{"fake-module1", "fake-module2", "fake-module3", "MODULES-IN-0-1"},
Patrice Arruda13848222019-04-22 17:12:02 -0700888 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700889 description: "build file in 2nd level parent directory",
890 dirsInTrees: []string{"0/1/2"},
891 buildFiles: []string{"0/Android.bp"},
892 args: []string{},
893 curDir: "0/1/2",
894 tidyOnly: "",
895 expectedArgs: []string{"MODULES-IN-0"},
Patrice Arruda13848222019-04-22 17:12:02 -0700896 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700897 description: "build action executed at root directory",
898 dirsInTrees: []string{},
899 buildFiles: []string{},
900 rootSymlink: false,
901 args: []string{},
902 curDir: ".",
903 tidyOnly: "",
904 expectedArgs: []string{},
Patrice Arrudababa9a92019-07-03 10:47:34 -0700905 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700906 description: "build action executed at root directory in symlink",
907 dirsInTrees: []string{},
908 buildFiles: []string{},
909 rootSymlink: true,
910 args: []string{},
911 curDir: ".",
912 tidyOnly: "",
913 expectedArgs: []string{},
Patrice Arruda13848222019-04-22 17:12:02 -0700914 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700915 description: "build file not found",
916 dirsInTrees: []string{"0/1/2"},
917 buildFiles: []string{},
918 args: []string{},
919 curDir: "0/1/2",
920 tidyOnly: "",
921 expectedArgs: []string{"MODULES-IN-0-1-2"},
922 expectedErrStr: "Build file not found for 0/1/2 directory",
Patrice Arruda13848222019-04-22 17:12:02 -0700923 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700924 description: "GET-INSTALL-PATH specified,",
925 dirsInTrees: []string{"0/1/2"},
926 buildFiles: []string{"0/1/Android.mk"},
927 args: []string{"GET-INSTALL-PATH", "-j", "-k", "GET-INSTALL-PATH"},
928 curDir: "0/1/2",
929 tidyOnly: "",
930 expectedArgs: []string{"-j", "-k", "GET-INSTALL-PATH-IN-0-1"},
Patrice Arruda13848222019-04-22 17:12:02 -0700931 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700932 description: "tidy only environment variable specified,",
933 dirsInTrees: []string{"0/1/2"},
934 buildFiles: []string{"0/1/Android.mk"},
935 args: []string{"GET-INSTALL-PATH"},
936 curDir: "0/1/2",
937 tidyOnly: "true",
938 expectedArgs: []string{"tidy_only"},
Patrice Arruda13848222019-04-22 17:12:02 -0700939 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700940 description: "normal execution in root directory with args",
941 dirsInTrees: []string{},
942 buildFiles: []string{},
943 args: []string{"-j", "-k", "fake_module"},
944 curDir: "",
945 tidyOnly: "",
946 expectedArgs: []string{"-j", "-k", "fake_module"},
Patrice Arruda13848222019-04-22 17:12:02 -0700947 }}
948 for _, tt := range tests {
949 t.Run("build action BUILD_MODULES_IN_DIR, "+tt.description, func(t *testing.T) {
Dan Willemsence41e942019-07-29 23:39:30 -0700950 testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY)
Patrice Arruda13848222019-04-22 17:12:02 -0700951 })
952 }
953}
954
955func TestGetConfigArgsBuildModulesInDirectories(t *testing.T) {
956 tests := []buildActionTestCase{{
957 description: "normal execution in a directory",
958 dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
959 buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
960 args: []string{"3.1/", "3.2/", "3.3/"},
961 curDir: "0/1/2",
962 tidyOnly: "",
963 expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-2-3.3"},
Patrice Arruda13848222019-04-22 17:12:02 -0700964 }, {
965 description: "GET-INSTALL-PATH specified",
966 dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3"},
967 buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/Android.bp"},
968 args: []string{"GET-INSTALL-PATH", "2/3.1/", "2/3.2", "3"},
969 curDir: "0/1",
970 tidyOnly: "",
971 expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "GET-INSTALL-PATH-IN-0-1"},
Patrice Arruda13848222019-04-22 17:12:02 -0700972 }, {
973 description: "tidy only environment variable specified",
974 dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
975 buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
976 args: []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3"},
977 curDir: "0/1/2",
978 tidyOnly: "1",
979 expectedArgs: []string{"tidy_only"},
Patrice Arruda13848222019-04-22 17:12:02 -0700980 }, {
981 description: "normal execution from top dir directory",
982 dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
983 buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/3/Android.bp", "0/2/Android.bp"},
Patrice Arrudababa9a92019-07-03 10:47:34 -0700984 rootSymlink: false,
985 args: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
986 curDir: ".",
987 tidyOnly: "",
988 expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
Patrice Arrudababa9a92019-07-03 10:47:34 -0700989 }, {
990 description: "normal execution from top dir directory in symlink",
991 dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
992 buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/3/Android.bp", "0/2/Android.bp"},
993 rootSymlink: true,
Patrice Arruda13848222019-04-22 17:12:02 -0700994 args: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
995 curDir: ".",
996 tidyOnly: "",
997 expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
Patrice Arruda13848222019-04-22 17:12:02 -0700998 }}
999 for _, tt := range tests {
1000 t.Run("build action BUILD_MODULES_IN_DIRS, "+tt.description, func(t *testing.T) {
Dan Willemsence41e942019-07-29 23:39:30 -07001001 testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES)
Patrice Arruda13848222019-04-22 17:12:02 -07001002 })
1003 }
1004}
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001005
1006func TestBuildConfig(t *testing.T) {
1007 tests := []struct {
1008 name string
1009 environ Environment
Yu Liue737a992021-10-04 13:21:41 -07001010 arguments []string
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001011 useBazel bool
Chris Parsonsef615e52022-08-18 22:04:11 -04001012 bazelDevMode bool
1013 bazelProdMode bool
MarkDacekb78465d2022-10-18 20:10:16 +00001014 bazelStagingMode bool
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001015 expectedBuildConfig *smpb.BuildConfig
1016 }{
1017 {
1018 name: "none set",
1019 environ: Environment{},
1020 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001021 ForceUseGoma: proto.Bool(false),
1022 UseGoma: proto.Bool(false),
1023 UseRbe: proto.Bool(false),
1024 BazelMixedBuild: proto.Bool(false),
1025 ForceDisableBazelMixedBuild: proto.Bool(false),
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001026 },
1027 },
1028 {
1029 name: "force use goma",
1030 environ: Environment{"FORCE_USE_GOMA=1"},
1031 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001032 ForceUseGoma: proto.Bool(true),
1033 UseGoma: proto.Bool(false),
1034 UseRbe: proto.Bool(false),
1035 BazelMixedBuild: proto.Bool(false),
1036 ForceDisableBazelMixedBuild: proto.Bool(false),
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001037 },
1038 },
1039 {
1040 name: "use goma",
1041 environ: Environment{"USE_GOMA=1"},
1042 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001043 ForceUseGoma: proto.Bool(false),
1044 UseGoma: proto.Bool(true),
1045 UseRbe: proto.Bool(false),
1046 BazelMixedBuild: proto.Bool(false),
1047 ForceDisableBazelMixedBuild: proto.Bool(false),
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001048 },
1049 },
1050 {
1051 name: "use rbe",
1052 environ: Environment{"USE_RBE=1"},
1053 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001054 ForceUseGoma: proto.Bool(false),
1055 UseGoma: proto.Bool(false),
1056 UseRbe: proto.Bool(true),
1057 BazelMixedBuild: proto.Bool(false),
1058 ForceDisableBazelMixedBuild: proto.Bool(false),
1059 },
1060 },
1061 {
1062 name: "disable mixed builds",
1063 environ: Environment{"BUILD_BROKEN_DISABLE_BAZEL=1"},
1064 expectedBuildConfig: &smpb.BuildConfig{
1065 ForceUseGoma: proto.Bool(false),
1066 UseGoma: proto.Bool(false),
1067 UseRbe: proto.Bool(false),
1068 BazelMixedBuild: proto.Bool(false),
1069 ForceDisableBazelMixedBuild: proto.Bool(true),
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001070 },
1071 },
1072 {
1073 name: "use bazel as ninja",
1074 environ: Environment{},
1075 useBazel: true,
1076 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001077 ForceUseGoma: proto.Bool(false),
1078 UseGoma: proto.Bool(false),
1079 UseRbe: proto.Bool(false),
1080 BazelMixedBuild: proto.Bool(false),
1081 ForceDisableBazelMixedBuild: proto.Bool(false),
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001082 },
1083 },
1084 {
Chris Parsonsef615e52022-08-18 22:04:11 -04001085 name: "bazel mixed build from dev mode",
1086 environ: Environment{},
1087 bazelDevMode: true,
1088 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001089 ForceUseGoma: proto.Bool(false),
1090 UseGoma: proto.Bool(false),
1091 UseRbe: proto.Bool(false),
1092 BazelMixedBuild: proto.Bool(true),
1093 ForceDisableBazelMixedBuild: proto.Bool(false),
Chris Parsonsef615e52022-08-18 22:04:11 -04001094 },
1095 },
1096 {
1097 name: "bazel mixed build from prod mode",
1098 environ: Environment{},
1099 bazelProdMode: true,
1100 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001101 ForceUseGoma: proto.Bool(false),
1102 UseGoma: proto.Bool(false),
1103 UseRbe: proto.Bool(false),
1104 BazelMixedBuild: proto.Bool(true),
1105 ForceDisableBazelMixedBuild: proto.Bool(false),
Chris Parsonsef615e52022-08-18 22:04:11 -04001106 },
1107 },
1108 {
MarkDacekb78465d2022-10-18 20:10:16 +00001109 name: "bazel mixed build from staging mode",
1110 environ: Environment{},
1111 bazelStagingMode: true,
1112 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001113 ForceUseGoma: proto.Bool(false),
1114 UseGoma: proto.Bool(false),
1115 UseRbe: proto.Bool(false),
1116 BazelMixedBuild: proto.Bool(true),
1117 ForceDisableBazelMixedBuild: proto.Bool(false),
MarkDacekb78465d2022-10-18 20:10:16 +00001118 },
1119 },
1120 {
Yu Liue737a992021-10-04 13:21:41 -07001121 name: "specified targets",
1122 environ: Environment{},
1123 useBazel: true,
1124 arguments: []string{"droid", "dist"},
1125 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001126 ForceUseGoma: proto.Bool(false),
1127 UseGoma: proto.Bool(false),
1128 UseRbe: proto.Bool(false),
1129 BazelMixedBuild: proto.Bool(false),
1130 Targets: []string{"droid", "dist"},
1131 ForceDisableBazelMixedBuild: proto.Bool(false),
Yu Liue737a992021-10-04 13:21:41 -07001132 },
1133 },
1134 {
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001135 name: "all set",
1136 environ: Environment{
1137 "FORCE_USE_GOMA=1",
1138 "USE_GOMA=1",
1139 "USE_RBE=1",
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001140 "BUILD_BROKEN_DISABLE_BAZEL=1",
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001141 },
Chris Parsonsef615e52022-08-18 22:04:11 -04001142 useBazel: true,
1143 bazelDevMode: true,
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001144 expectedBuildConfig: &smpb.BuildConfig{
Romain Jobredeaux0a7529b2022-10-26 12:56:41 -04001145 ForceUseGoma: proto.Bool(true),
1146 UseGoma: proto.Bool(true),
1147 UseRbe: proto.Bool(true),
1148 BazelMixedBuild: proto.Bool(true),
1149 ForceDisableBazelMixedBuild: proto.Bool(true),
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001150 },
1151 },
1152 }
1153
Chris Parsonsef615e52022-08-18 22:04:11 -04001154 ctx := testContext()
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001155 for _, tc := range tests {
1156 t.Run(tc.name, func(t *testing.T) {
1157 c := &configImpl{
MarkDacekb78465d2022-10-18 20:10:16 +00001158 environ: &tc.environ,
1159 bazelDevMode: tc.bazelDevMode,
1160 bazelProdMode: tc.bazelProdMode,
1161 bazelStagingMode: tc.bazelStagingMode,
1162 arguments: tc.arguments,
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001163 }
1164 config := Config{c}
Chris Parsonsef615e52022-08-18 22:04:11 -04001165 checkBazelMode(ctx, config)
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001166 actualBuildConfig := buildConfig(config)
1167 if expected := tc.expectedBuildConfig; !proto.Equal(expected, actualBuildConfig) {
Chris Parsonsef615e52022-08-18 22:04:11 -04001168 t.Errorf("Build config mismatch.\n"+
1169 "Expected build config: %#v\n"+
1170 "Actual build config: %#v", prototext.Format(expected), prototext.Format(actualBuildConfig))
Liz Kammerca9cb2e2021-07-14 15:29:57 -04001171 }
1172 })
1173 }
1174}
Yu Liu6e13b402021-07-27 14:29:06 -07001175
1176func TestGetMetricsUploaderApp(t *testing.T) {
1177
1178 metricsUploaderDir := "metrics_uploader_dir"
1179 metricsUploaderBinary := "metrics_uploader_binary"
1180 metricsUploaderPath := filepath.Join(metricsUploaderDir, metricsUploaderBinary)
1181 tests := []struct {
1182 description string
1183 environ Environment
1184 createFiles bool
1185 expected string
1186 }{{
1187 description: "Uploader binary exist",
1188 environ: Environment{"METRICS_UPLOADER=" + metricsUploaderPath},
1189 createFiles: true,
1190 expected: metricsUploaderPath,
1191 }, {
1192 description: "Uploader binary not exist",
1193 environ: Environment{"METRICS_UPLOADER=" + metricsUploaderPath},
1194 createFiles: false,
1195 expected: "",
1196 }, {
1197 description: "Uploader binary variable not set",
1198 createFiles: true,
1199 expected: "",
1200 }}
1201
1202 for _, tt := range tests {
1203 t.Run(tt.description, func(t *testing.T) {
1204 defer logger.Recover(func(err error) {
1205 t.Fatalf("got unexpected error: %v", err)
1206 })
1207
1208 // Create the root source tree.
1209 topDir, err := ioutil.TempDir("", "")
1210 if err != nil {
1211 t.Fatalf("failed to create temp dir: %v", err)
1212 }
1213 defer os.RemoveAll(topDir)
1214
1215 expected := tt.expected
1216 if len(expected) > 0 {
1217 expected = filepath.Join(topDir, expected)
1218 }
1219
1220 if tt.createFiles {
1221 if err := os.MkdirAll(filepath.Join(topDir, metricsUploaderDir), 0755); err != nil {
1222 t.Errorf("failed to create %s directory: %v", metricsUploaderDir, err)
1223 }
1224 if err := ioutil.WriteFile(filepath.Join(topDir, metricsUploaderPath), []byte{}, 0644); err != nil {
1225 t.Errorf("failed to create file %s: %v", expected, err)
1226 }
1227 }
1228
1229 actual := GetMetricsUploader(topDir, &tt.environ)
1230
1231 if actual != expected {
1232 t.Errorf("expecting: %s, actual: %s", expected, actual)
1233 }
1234 })
1235 }
1236}