• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/bash -eu
2
3set -o pipefail
4
5# This test exercises the bootstrapping process of the build system
6# in a source tree that only contains enough files for Bazel and Soong to work.
7
8source "$(dirname "$0")/lib.sh"
9
10readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel"
11
12function test_smoke {
13  setup
14  run_soong
15}
16
17function test_null_build() {
18  setup
19  run_soong
20  local -r bootstrap_mtime1=$(stat -c "%y" out/soong/bootstrap.ninja)
21  local -r output_mtime1=$(stat -c "%y" out/soong/build.ninja)
22  run_soong
23  local -r bootstrap_mtime2=$(stat -c "%y" out/soong/bootstrap.ninja)
24  local -r output_mtime2=$(stat -c "%y" out/soong/build.ninja)
25
26  if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
27    # Bootstrapping is always done. It doesn't take a measurable amount of time.
28    fail "Bootstrap Ninja file did not change on null build"
29  fi
30
31  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
32    fail "Output Ninja file changed on null build"
33  fi
34}
35
36function test_soong_build_rebuilt_if_blueprint_changes() {
37  setup
38  run_soong
39  local -r mtime1=$(stat -c "%y" out/soong/bootstrap.ninja)
40
41  sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
42
43  run_soong
44  local -r mtime2=$(stat -c "%y" out/soong/bootstrap.ninja)
45
46  if [[ "$mtime1" == "$mtime2" ]]; then
47    fail "Bootstrap Ninja file did not change"
48  fi
49}
50
51function test_change_android_bp() {
52  setup
53  mkdir -p a
54  cat > a/Android.bp <<'EOF'
55python_binary_host {
56  name: "my_little_binary_host",
57  srcs: ["my_little_binary_host.py"]
58}
59EOF
60  touch a/my_little_binary_host.py
61  run_soong
62
63  grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
64
65  cat > a/Android.bp <<'EOF'
66python_binary_host {
67  name: "my_great_binary_host",
68  srcs: ["my_great_binary_host.py"]
69}
70EOF
71  touch a/my_great_binary_host.py
72  run_soong
73
74  grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
75  grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
76}
77
78function test_add_android_bp() {
79  setup
80  run_soong
81  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
82
83  mkdir -p a
84  cat > a/Android.bp <<'EOF'
85python_binary_host {
86  name: "my_little_binary_host",
87  srcs: ["my_little_binary_host.py"]
88}
89EOF
90  touch a/my_little_binary_host.py
91  run_soong
92
93  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
94  if [[ "$mtime1" == "$mtime2" ]]; then
95    fail "Output Ninja file did not change"
96  fi
97
98  grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
99
100  run_soong
101}
102
103function test_delete_android_bp() {
104  setup
105  mkdir -p a
106  cat > a/Android.bp <<'EOF'
107python_binary_host {
108  name: "my_little_binary_host",
109  srcs: ["my_little_binary_host.py"]
110}
111EOF
112  touch a/my_little_binary_host.py
113  run_soong
114
115  grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
116
117  rm a/Android.bp
118  run_soong
119
120  if grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja; then
121    fail "Old module in output"
122  fi
123}
124
125# Test that an incremental build with a glob doesn't rerun soong_build, and
126# only regenerates the globs on the first but not the second incremental build.
127function test_glob_noop_incremental() {
128  setup
129
130  # This test needs to start from a clean build, but setup creates an
131  # initialized tree that has already been built once.  Clear the out
132  # directory to start from scratch (see b/185591972)
133  rm -rf out
134
135  mkdir -p a
136  cat > a/Android.bp <<'EOF'
137python_binary_host {
138  name: "my_little_binary_host",
139  srcs: ["*.py"],
140}
141EOF
142  touch a/my_little_binary_host.py
143  run_soong
144  local -r ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
145
146  local glob_deps_file=out/soong/globs/build/0.d
147
148  if [ -e "$glob_deps_file" ]; then
149    fail "Glob deps file unexpectedly written on first build"
150  fi
151
152  run_soong
153  local -r ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
154
155  # There is an ineffiencency in glob that requires bpglob to rerun once for each glob to update
156  # the entry in the .ninja_log.  It doesn't update the output file, but we can detect the rerun
157  # by checking if the deps file was created.
158  if [ ! -e "$glob_deps_file" ]; then
159    fail "Glob deps file missing after second build"
160  fi
161
162  local -r glob_deps_mtime2=$(stat -c "%y" "$glob_deps_file")
163
164  if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
165    fail "Ninja file rewritten on null incremental build"
166  fi
167
168  run_soong
169  local -r ninja_mtime3=$(stat -c "%y" out/soong/build.ninja)
170  local -r glob_deps_mtime3=$(stat -c "%y" "$glob_deps_file")
171
172  if [[ "$ninja_mtime2" != "$ninja_mtime3" ]]; then
173    fail "Ninja file rewritten on null incremental build"
174  fi
175
176  # The bpglob commands should not rerun after the first incremental build.
177  if [[ "$glob_deps_mtime2" != "$glob_deps_mtime3" ]]; then
178    fail "Glob deps file rewritten on second null incremental build"
179  fi
180}
181
182function test_add_file_to_glob() {
183  setup
184
185  mkdir -p a
186  cat > a/Android.bp <<'EOF'
187python_binary_host {
188  name: "my_little_binary_host",
189  srcs: ["*.py"],
190}
191EOF
192  touch a/my_little_binary_host.py
193  run_soong
194  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
195
196  touch a/my_little_library.py
197  run_soong
198
199  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
200  if [[ "$mtime1" == "$mtime2" ]]; then
201    fail "Output Ninja file did not change"
202  fi
203
204  grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
205}
206
207function test_soong_build_rerun_iff_environment_changes() {
208  setup
209
210  mkdir -p cherry
211  cat > cherry/Android.bp <<'EOF'
212bootstrap_go_package {
213  name: "cherry",
214  pkgPath: "android/soong/cherry",
215  deps: [
216    "blueprint",
217    "soong",
218    "soong-android",
219  ],
220  srcs: [
221    "cherry.go",
222  ],
223  pluginFor: ["soong_build"],
224}
225EOF
226
227  cat > cherry/cherry.go <<'EOF'
228package cherry
229
230import (
231  "android/soong/android"
232  "github.com/google/blueprint"
233)
234
235var (
236  pctx = android.NewPackageContext("cherry")
237)
238
239func init() {
240  android.RegisterSingletonType("cherry", CherrySingleton)
241}
242
243func CherrySingleton() android.Singleton {
244  return &cherrySingleton{}
245}
246
247type cherrySingleton struct{}
248
249func (p *cherrySingleton) GenerateBuildActions(ctx android.SingletonContext) {
250  cherryRule := ctx.Rule(pctx, "cherry",
251    blueprint.RuleParams{
252      Command: "echo CHERRY IS " + ctx.Config().Getenv("CHERRY") + " > ${out}",
253      CommandDeps: []string{},
254      Description: "Cherry",
255    })
256
257  outputFile := android.PathForOutput(ctx, "cherry", "cherry.txt")
258  var deps android.Paths
259
260  ctx.Build(pctx, android.BuildParams{
261    Rule: cherryRule,
262    Output: outputFile,
263    Inputs: deps,
264  })
265}
266EOF
267
268  export CHERRY=TASTY
269  run_soong
270  grep -q "CHERRY IS TASTY" out/soong/build.ninja \
271    || fail "first value of environment variable is not used"
272
273  export CHERRY=RED
274  run_soong
275  grep -q "CHERRY IS RED" out/soong/build.ninja \
276    || fail "second value of environment variable not used"
277  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
278
279  run_soong
280  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
281  if [[ "$mtime1" != "$mtime2" ]]; then
282    fail "Output Ninja file changed when environment variable did not"
283  fi
284
285}
286
287function test_create_global_include_directory() {
288  setup
289  run_soong
290  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
291
292  # Soong needs to know if top level directories like hardware/ exist for use
293  # as global include directories.  Make sure that doesn't cause regens for
294  # unrelated changes to the top level directory.
295  mkdir -p system/core
296
297  run_soong
298  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
299  if [[ "$mtime1" != "$mtime2" ]]; then
300    fail "Output Ninja file changed when top level directory changed"
301  fi
302
303  # Make sure it does regen if a missing directory in the path of a global
304  # include directory is added.
305  mkdir -p system/core/include
306
307  run_soong
308  local -r mtime3=$(stat -c "%y" out/soong/build.ninja)
309  if [[ "$mtime2" = "$mtime3" ]]; then
310    fail "Output Ninja file did not change when global include directory created"
311  fi
312
313}
314
315function test_add_file_to_soong_build() {
316  setup
317  run_soong
318  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
319
320  mkdir -p a
321  cat > a/Android.bp <<'EOF'
322bootstrap_go_package {
323  name: "picard-soong-rules",
324  pkgPath: "android/soong/picard",
325  deps: [
326    "blueprint",
327    "soong",
328    "soong-android",
329  ],
330  srcs: [
331    "picard.go",
332  ],
333  pluginFor: ["soong_build"],
334}
335EOF
336
337  cat > a/picard.go <<'EOF'
338package picard
339
340import (
341  "android/soong/android"
342  "github.com/google/blueprint"
343)
344
345var (
346  pctx = android.NewPackageContext("picard")
347)
348
349func init() {
350  android.RegisterSingletonType("picard", PicardSingleton)
351}
352
353func PicardSingleton() android.Singleton {
354  return &picardSingleton{}
355}
356
357type picardSingleton struct{}
358
359func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
360  picardRule := ctx.Rule(pctx, "picard",
361    blueprint.RuleParams{
362      Command: "echo Make it so. > ${out}",
363      CommandDeps: []string{},
364      Description: "Something quotable",
365    })
366
367  outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
368  var deps android.Paths
369
370  ctx.Build(pctx, android.BuildParams{
371    Rule: picardRule,
372    Output: outputFile,
373    Inputs: deps,
374  })
375}
376
377EOF
378
379  run_soong
380  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
381  if [[ "$mtime1" == "$mtime2" ]]; then
382    fail "Output Ninja file did not change"
383  fi
384
385  grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
386}
387
388# Tests a glob in a build= statement in an Android.bp file, which is interpreted
389# during bootstrapping.
390function test_glob_during_bootstrapping() {
391  setup
392
393  mkdir -p a
394  cat > a/Android.bp <<'EOF'
395build=["foo*.bp"]
396EOF
397  cat > a/fooa.bp <<'EOF'
398bootstrap_go_package {
399  name: "picard-soong-rules",
400  pkgPath: "android/soong/picard",
401  deps: [
402    "blueprint",
403    "soong",
404    "soong-android",
405  ],
406  srcs: [
407    "picard.go",
408  ],
409  pluginFor: ["soong_build"],
410}
411EOF
412
413  cat > a/picard.go <<'EOF'
414package picard
415
416import (
417  "android/soong/android"
418  "github.com/google/blueprint"
419)
420
421var (
422  pctx = android.NewPackageContext("picard")
423)
424
425func init() {
426  android.RegisterSingletonType("picard", PicardSingleton)
427}
428
429func PicardSingleton() android.Singleton {
430  return &picardSingleton{}
431}
432
433type picardSingleton struct{}
434
435var Message = "Make it so."
436
437func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
438  picardRule := ctx.Rule(pctx, "picard",
439    blueprint.RuleParams{
440      Command: "echo " + Message + " > ${out}",
441      CommandDeps: []string{},
442      Description: "Something quotable",
443    })
444
445  outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
446  var deps android.Paths
447
448  ctx.Build(pctx, android.BuildParams{
449    Rule: picardRule,
450    Output: outputFile,
451    Inputs: deps,
452  })
453}
454
455EOF
456
457  run_soong
458  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
459
460  grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
461
462  cat > a/foob.bp <<'EOF'
463bootstrap_go_package {
464  name: "worf-soong-rules",
465  pkgPath: "android/soong/worf",
466  deps: [
467    "blueprint",
468    "soong",
469    "soong-android",
470    "picard-soong-rules",
471  ],
472  srcs: [
473    "worf.go",
474  ],
475  pluginFor: ["soong_build"],
476}
477EOF
478
479  cat > a/worf.go <<'EOF'
480package worf
481
482import "android/soong/picard"
483
484func init() {
485   picard.Message = "Engage."
486}
487EOF
488
489  run_soong
490  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
491  if [[ "$mtime1" == "$mtime2" ]]; then
492    fail "Output Ninja file did not change"
493  fi
494
495  grep -q "Engage" out/soong/build.ninja || fail "New action not present"
496
497  if grep -q "Make it so" out/soong/build.ninja; then
498    fail "Original action still present"
499  fi
500}
501
502function test_soong_docs_smoke() {
503  setup
504
505  run_soong soong_docs
506
507  [[ -e "out/soong/docs/soong_build.html" ]] || fail "Documentation for main page not created"
508  [[ -e "out/soong/docs/cc.html" ]] || fail "Documentation for C++ modules not created"
509}
510
511function test_null_build_after_soong_docs() {
512  setup
513
514  run_soong
515  local -r ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
516
517  run_soong soong_docs
518  local -r docs_mtime1=$(stat -c "%y" out/soong/docs/soong_build.html)
519
520  run_soong soong_docs
521  local -r docs_mtime2=$(stat -c "%y" out/soong/docs/soong_build.html)
522
523  if [[ "$docs_mtime1" != "$docs_mtime2" ]]; then
524    fail "Output Ninja file changed on null build"
525  fi
526
527  run_soong
528  local -r ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
529
530  if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
531    fail "Output Ninja file changed on null build"
532  fi
533}
534
535function test_write_to_source_tree {
536  setup
537  mkdir -p a
538  cat > a/Android.bp <<EOF
539genrule {
540  name: "write_to_source_tree",
541  out: ["write_to_source_tree"],
542  cmd: "touch file_in_source_tree && touch \$(out)",
543}
544EOF
545  readonly EXPECTED_OUT=out/soong/.intermediates/a/write_to_source_tree/gen/write_to_source_tree
546  readonly ERROR_LOG=${MOCK_TOP}/out/error.log
547  readonly ERROR_MSG="Read-only file system"
548  readonly ERROR_HINT_PATTERN="BUILD_BROKEN_SRC_DIR"
549  # Test in ReadOnly source tree
550  run_ninja BUILD_BROKEN_SRC_DIR_IS_WRITABLE=false ${EXPECTED_OUT} &> /dev/null && \
551    fail "Write to source tree should not work in a ReadOnly source tree"
552
553  if grep -q "${ERROR_MSG}" "${ERROR_LOG}" && grep -q "${ERROR_HINT_PATTERN}" "${ERROR_LOG}" ; then
554    echo Error message and error hint found in logs >/dev/null
555  else
556    fail "Did not find Read-only error AND error hint in error.log"
557  fi
558
559  # Test in ReadWrite source tree
560  run_ninja BUILD_BROKEN_SRC_DIR_IS_WRITABLE=true ${EXPECTED_OUT} &> /dev/null || \
561    fail "Write to source tree did not succeed in a ReadWrite source tree"
562
563  if  grep -q "${ERROR_MSG}\|${ERROR_HINT_PATTERN}" "${ERROR_LOG}" ; then
564    fail "Found read-only error OR error hint in error.log"
565  fi
566}
567
568function test_bp2build_smoke {
569  setup
570  run_soong bp2build
571  [[ -e out/soong/bp2build_workspace_marker ]] || fail "bp2build marker file not created"
572  [[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
573}
574
575function test_bp2build_generates_marker_file {
576  setup
577
578  run_soong bp2build
579
580  if [[ ! -f "./out/soong/bp2build_files_marker" ]]; then
581    fail "bp2build marker file was not generated"
582  fi
583
584  if [[ ! -f "./out/soong/bp2build_workspace_marker" ]]; then
585    fail "symlink forest marker file was not generated"
586  fi
587}
588
589function test_bp2build_add_irrelevant_file {
590  setup
591
592  mkdir -p a/b
593  touch a/b/c.txt
594  cat > a/b/Android.bp <<'EOF'
595filegroup {
596  name: "c",
597  srcs: ["c.txt"],
598  bazel_module: { bp2build_available: true },
599}
600EOF
601
602  run_soong bp2build
603  if [[ ! -e out/soong/bp2build/a/b/BUILD.bazel ]]; then
604    fail "BUILD file in symlink forest was not created";
605  fi
606
607  local -r mtime1=$(stat -c "%y" out/soong/bp2build/a/b/BUILD.bazel)
608
609  touch a/irrelevant.txt
610  run_soong bp2build
611  local -r mtime2=$(stat -c "%y" out/soong/bp2build/a/b/BUILD.bazel)
612
613  if [[ "$mtime1" != "$mtime2" ]]; then
614    fail "BUILD.bazel file was regenerated"
615  fi
616
617  if [[ ! -e "out/soong/workspace/a/irrelevant.txt" ]]; then
618    fail "New file was not symlinked into symlink forest"
619  fi
620}
621
622function test_bp2build_add_android_bp {
623  setup
624
625  mkdir -p a
626  touch a/a.txt
627  cat > a/Android.bp <<'EOF'
628filegroup {
629  name: "a",
630  srcs: ["a.txt"],
631  bazel_module: { bp2build_available: true },
632}
633EOF
634
635  run_soong bp2build
636  [[ -e out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not created"
637  [[ -L out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not symlinked"
638
639  mkdir -p b
640  touch b/b.txt
641  cat > b/Android.bp <<'EOF'
642filegroup {
643  name: "b",
644  srcs: ["b.txt"],
645  bazel_module: { bp2build_available: true },
646}
647EOF
648
649  run_soong bp2build
650  [[ -e out/soong/bp2build/b/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not created"
651  [[ -L out/soong/workspace/b/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not symlinked"
652}
653
654function test_bp2build_null_build {
655  setup
656
657  run_soong bp2build
658  local -r mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
659
660  run_soong bp2build
661  local -r mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
662
663  if [[ "$mtime1" != "$mtime2" ]]; then
664    fail "Output Ninja file changed on null build"
665  fi
666}
667
668function test_bp2build_add_to_glob {
669  setup
670
671  mkdir -p a
672  touch a/a1.txt
673  cat > a/Android.bp <<'EOF'
674filegroup {
675  name: "a",
676  srcs: ["*.txt"],
677  bazel_module: { bp2build_available: true },
678}
679EOF
680
681  run_soong bp2build
682  grep -q a1.txt "out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME}" || fail "a1.txt not in ${GENERATED_BUILD_FILE_NAME} file"
683
684  touch a/a2.txt
685  run_soong bp2build
686  grep -q a2.txt "out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME}" || fail "a2.txt not in ${GENERATED_BUILD_FILE_NAME} file"
687}
688
689function test_multiple_soong_build_modes() {
690  setup
691  run_soong json-module-graph bp2build nothing
692  if [[ ! -f "out/soong/bp2build_workspace_marker" ]]; then
693    fail "bp2build marker file was not generated"
694  fi
695
696
697  if [[ ! -f "out/soong/module-graph.json" ]]; then
698    fail "JSON file was not created"
699  fi
700
701  if [[ ! -f "out/soong/build.ninja" ]]; then
702    fail "Main build.ninja file was not created"
703  fi
704}
705
706function test_dump_json_module_graph() {
707  setup
708  run_soong json-module-graph
709  if [[ ! -r "out/soong/module-graph.json" ]]; then
710    fail "JSON file was not created"
711  fi
712}
713
714function test_json_module_graph_back_and_forth_null_build() {
715  setup
716
717  run_soong
718  local -r ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
719
720  run_soong json-module-graph
721  local -r json_mtime1=$(stat -c "%y" out/soong/module-graph.json)
722
723  run_soong
724  local -r ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
725  if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
726    fail "Output Ninja file changed after writing JSON module graph"
727  fi
728
729  run_soong json-module-graph
730  local -r json_mtime2=$(stat -c "%y" out/soong/module-graph.json)
731  if [[ "$json_mtime1" != "$json_mtime2" ]]; then
732    fail "JSON module graph file changed after writing Ninja file"
733  fi
734
735}
736
737function test_bp2build_bazel_workspace_structure {
738  setup
739
740  mkdir -p a/b
741  touch a/a.txt
742  touch a/b/b.txt
743  cat > a/b/Android.bp <<'EOF'
744filegroup {
745  name: "b",
746  srcs: ["b.txt"],
747  bazel_module: { bp2build_available: true },
748}
749EOF
750
751  run_soong bp2build
752  [[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
753  [[ -d out/soong/workspace/a/b ]] || fail "module directory not a directory"
754  [[ -L "out/soong/workspace/a/b/${GENERATED_BUILD_FILE_NAME}" ]] || fail "${GENERATED_BUILD_FILE_NAME} file not symlinked"
755  [[ "$(readlink -f out/soong/workspace/a/b/${GENERATED_BUILD_FILE_NAME})" =~ "bp2build/a/b/${GENERATED_BUILD_FILE_NAME}"$ ]] \
756    || fail "BUILD files symlinked at the wrong place"
757  [[ -L out/soong/workspace/a/b/b.txt ]] || fail "a/b/b.txt not symlinked"
758  [[ -L out/soong/workspace/a/a.txt ]] || fail "a/b/a.txt not symlinked"
759  [[ ! -e out/soong/workspace/out ]] || fail "out directory symlinked"
760}
761
762function test_bp2build_bazel_workspace_add_file {
763  setup
764
765  mkdir -p a
766  touch a/a.txt
767  cat > a/Android.bp <<EOF
768filegroup {
769  name: "a",
770  srcs: ["a.txt"],
771  bazel_module: { bp2build_available: true },
772}
773EOF
774
775  run_soong bp2build
776
777  touch a/a2.txt  # No reference in the .bp file needed
778  run_soong bp2build
779  [[ -L out/soong/workspace/a/a2.txt ]] || fail "a/a2.txt not symlinked"
780}
781
782function test_bp2build_build_file_precedence {
783  setup
784
785  mkdir -p a
786  touch a/a.txt
787  touch a/${GENERATED_BUILD_FILE_NAME}
788  cat > a/Android.bp <<EOF
789filegroup {
790  name: "a",
791  srcs: ["a.txt"],
792  bazel_module: { bp2build_available: true },
793}
794EOF
795
796  run_soong bp2build
797  [[ -L "out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME}" ]] || fail "${GENERATED_BUILD_FILE_NAME} file not symlinked"
798  [[ "$(readlink -f out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME})" =~ "bp2build/a/${GENERATED_BUILD_FILE_NAME}"$ ]] \
799    || fail "${GENERATED_BUILD_FILE_NAME} files symlinked to the wrong place"
800}
801
802function test_bp2build_fails_fast {
803  setup
804
805  mkdir -p "a/${GENERATED_BUILD_FILE_NAME}"
806  cat > a/Android.bp <<EOF
807filegroup {
808  name: "a",
809  srcs: ["a.txt"],
810  bazel_module: { bp2build_available: true },
811}
812EOF
813
814  mkdir -p "b/${GENERATED_BUILD_FILE_NAME}"
815  cat > b/Android.bp <<EOF
816filegroup {
817  name: "b",
818  srcs: ["b.txt"],
819  bazel_module: { bp2build_available: true },
820}
821EOF
822
823  if run_soong bp2build >& "$MOCK_TOP/errors"; then
824    fail "Build should have failed"
825  fi
826
827  # we should expect at least one error
828  grep -q -E "(a|b)/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for ${GENERATED_BUILD_FILE_NAME} not found"
829}
830
831function test_bp2build_back_and_forth_null_build {
832  setup
833
834  run_soong
835  local -r output_mtime1=$(stat -c "%y" out/soong/build.ninja)
836
837  run_soong bp2build
838  local -r output_mtime2=$(stat -c "%y" out/soong/build.ninja)
839  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
840    fail "Output Ninja file changed when switching to bp2build"
841  fi
842
843  local -r marker_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
844
845  run_soong
846  local -r output_mtime3=$(stat -c "%y" out/soong/build.ninja)
847  local -r marker_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
848  if [[ "$output_mtime1" != "$output_mtime3" ]]; then
849    fail "Output Ninja file changed when switching to regular build from bp2build"
850  fi
851  if [[ "$marker_mtime1" != "$marker_mtime2" ]]; then
852    fail "bp2build marker file changed when switching to regular build from bp2build"
853  fi
854
855  run_soong bp2build
856  local -r output_mtime4=$(stat -c "%y" out/soong/build.ninja)
857  local -r marker_mtime3=$(stat -c "%y" out/soong/bp2build_workspace_marker)
858  if [[ "$output_mtime1" != "$output_mtime4" ]]; then
859    fail "Output Ninja file changed when switching back to bp2build"
860  fi
861  if [[ "$marker_mtime1" != "$marker_mtime3" ]]; then
862    fail "bp2build marker file changed when switching back to bp2build"
863  fi
864}
865
866function test_queryview_smoke() {
867  setup
868
869  run_soong queryview
870  [[ -e out/soong/queryview/WORKSPACE ]] || fail "queryview WORKSPACE file not created"
871
872}
873
874function test_queryview_null_build() {
875  setup
876
877  run_soong queryview
878  local -r output_mtime1=$(stat -c "%y" out/soong/queryview.marker)
879
880  run_soong queryview
881  local -r output_mtime2=$(stat -c "%y" out/soong/queryview.marker)
882
883  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
884    fail "Queryview marker file changed on null build"
885  fi
886}
887
888# This test verifies that adding a new glob to a blueprint file only
889# causes build.ninja to be regenerated on the *next* build, and *not*
890# the build after. (This is a regression test for a bug where globs
891# resulted in two successive regenerations.)
892function test_new_glob_incrementality {
893  setup
894
895  run_soong nothing
896  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
897
898  mkdir -p globdefpkg/
899  cat > globdefpkg/Android.bp <<'EOF'
900filegroup {
901  name: "fg_with_glob",
902  srcs: ["*.txt"],
903}
904EOF
905
906  run_soong nothing
907  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
908
909  if [[ "$mtime1" == "$mtime2" ]]; then
910    fail "Ninja file was not regenerated, despite a new bp file"
911  fi
912
913  run_soong nothing
914  local -r mtime3=$(stat -c "%y" out/soong/build.ninja)
915
916  if [[ "$mtime2" != "$mtime3" ]]; then
917    fail "Ninja file was regenerated despite no previous bp changes"
918  fi
919}
920
921scan_and_run_tests
922