blob: 9d8769780623020f5c9b2e2b7b98f6a431dd5e81 [file] [log] [blame]
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +01001#!/bin/bash -eu
2
3# This test exercises the bootstrapping process of the build system
4# in a source tree that only contains enough files for Bazel and Soong to work.
5
6HARDWIRED_MOCK_TOP=
Lukacs T. Berki720b3962021-03-17 13:34:30 +01007# Uncomment this to be able to view the source tree after a test is run
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +01008# HARDWIRED_MOCK_TOP=/tmp/td
9
10REAL_TOP="$(readlink -f "$(dirname "$0")"/../..)"
11
12function fail {
13 echo ERROR: $1
14 exit 1
15}
16
17function copy_directory() {
18 local dir="$1"
19 local parent="$(dirname "$dir")"
20
21 mkdir -p "$MOCK_TOP/$parent"
22 cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
23}
24
25function symlink_file() {
26 local file="$1"
27
28 mkdir -p "$MOCK_TOP/$(dirname "$file")"
29 ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
30}
31
32function symlink_directory() {
33 local dir="$1"
34
35 mkdir -p "$MOCK_TOP/$dir"
36 # We need to symlink the contents of the directory individually instead of
37 # using one symlink for the whole directory because finder.go doesn't follow
38 # symlinks when looking for Android.bp files
39 for i in $(ls "$REAL_TOP/$dir"); do
40 local target="$MOCK_TOP/$dir/$i"
41 local source="$REAL_TOP/$dir/$i"
42
43 if [[ -e "$target" ]]; then
44 if [[ ! -d "$source" || ! -d "$target" ]]; then
45 fail "Trying to symlink $dir twice"
46 fi
47 else
48 ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
49 fi
50 done
51}
52
53function setup_bazel() {
54 copy_directory build/bazel
55
56 symlink_directory prebuilts/bazel
57 symlink_directory prebuilts/jdk
58
59 symlink_file WORKSPACE
60 symlink_file tools/bazel
61}
62
63function setup() {
64 if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
65 MOCK_TOP="$HARDWIRED_MOCK_TOP"
66 rm -fr "$MOCK_TOP"
67 mkdir -p "$MOCK_TOP"
68 else
69 MOCK_TOP=$(mktemp -t -d st.XXXXX)
70 trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
71 fi
72
73 echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
74 cd "$MOCK_TOP"
75
76 copy_directory build/blueprint
77 copy_directory build/soong
78
79 symlink_directory prebuilts/go
80 symlink_directory prebuilts/build-tools
81 symlink_directory external/golang-protobuf
82
83 touch "$MOCK_TOP/Android.bp"
84
85 export ALLOW_MISSING_DEPENDENCIES=true
86
87 mkdir -p out/soong
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +010088}
89
90function run_soong() {
91 build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
92}
93
94function test_smoke {
95 setup
96 run_soong
97}
98
99function test_bazel_smoke {
100 setup
101 setup_bazel
102
103 tools/bazel info
104
105}
106function test_null_build() {
107 setup
108 run_soong
109 local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
110 local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
111 run_soong
112 local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
113 local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
114
115 if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
116 # Bootstrapping is always done. It doesn't take a measurable amount of time.
117 fail "Bootstrap Ninja file did not change on null build"
118 fi
119
120 if [[ "$output_mtime1" != "$output_mtime2" ]]; then
121 fail "Output Ninja file changed on null build"
122 fi
123}
124
125function test_soong_build_rebuilt_if_blueprint_changes() {
126 setup
127 run_soong
128 local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
129
130 sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
131
132 run_soong
133 local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
134
135 if [[ "$mtime1" == "$mtime2" ]]; then
136 fail "Bootstrap Ninja file did not change"
137 fi
138}
139
140function test_change_android_bp() {
141 setup
142 mkdir -p a
143 cat > a/Android.bp <<'EOF'
144python_binary_host {
145 name: "my_little_binary_host",
146 srcs: ["my_little_binary_host.py"]
147}
148EOF
149 touch a/my_little_binary_host.py
150 run_soong
151
152 grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
153
154 cat > a/Android.bp <<'EOF'
155python_binary_host {
156 name: "my_great_binary_host",
157 srcs: ["my_great_binary_host.py"]
158}
159EOF
160 touch a/my_great_binary_host.py
161 run_soong
162
163 grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
164 grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
165}
166
167
168function test_add_android_bp() {
169 setup
170 run_soong
171 local mtime1=$(stat -c "%y" out/soong/build.ninja)
172
173 mkdir -p a
174 cat > a/Android.bp <<'EOF'
175python_binary_host {
176 name: "my_little_binary_host",
177 srcs: ["my_little_binary_host.py"]
178}
179EOF
180 touch a/my_little_binary_host.py
181 run_soong
182
183 local mtime2=$(stat -c "%y" out/soong/build.ninja)
184 if [[ "$mtime1" == "$mtime2" ]]; then
185 fail "Output Ninja file did not change"
186 fi
187
188 grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
189
190 run_soong
191}
192
193function test_delete_android_bp() {
194 setup
195 mkdir -p a
196 cat > a/Android.bp <<'EOF'
197python_binary_host {
198 name: "my_little_binary_host",
199 srcs: ["my_little_binary_host.py"]
200}
201EOF
202 touch a/my_little_binary_host.py
203 run_soong
204
205 grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
206
207 rm a/Android.bp
208 run_soong
209
210 grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja && fail "Old module in output"
211}
212
213function test_add_file_to_glob() {
214 setup
215
216 mkdir -p a
217 cat > a/Android.bp <<'EOF'
218python_binary_host {
219 name: "my_little_binary_host",
220 srcs: ["*.py"],
221}
222EOF
223 touch a/my_little_binary_host.py
224 run_soong
225 local mtime1=$(stat -c "%y" out/soong/build.ninja)
226
227 touch a/my_little_library.py
228 run_soong
229
230 local mtime2=$(stat -c "%y" out/soong/build.ninja)
231 if [[ "$mtime1" == "$mtime2" ]]; then
232 fail "Output Ninja file did not change"
233 fi
234
235 grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
236}
237
Lukacs T. Berkif0b3b942021-03-23 11:46:47 +0100238function test_soong_build_rerun_iff_environment_changes() {
239 setup
240
241 mkdir -p cherry
242 cat > cherry/Android.bp <<'EOF'
243bootstrap_go_package {
244 name: "cherry",
245 pkgPath: "android/soong/cherry",
246 deps: [
247 "blueprint",
248 "soong",
249 "soong-android",
250 ],
251 srcs: [
252 "cherry.go",
253 ],
254 pluginFor: ["soong_build"],
255}
256EOF
257
258 cat > cherry/cherry.go <<'EOF'
259package cherry
260
261import (
262 "android/soong/android"
263 "github.com/google/blueprint"
264)
265
266var (
267 pctx = android.NewPackageContext("cherry")
268)
269
270func init() {
271 android.RegisterSingletonType("cherry", CherrySingleton)
272}
273
274func CherrySingleton() android.Singleton {
275 return &cherrySingleton{}
276}
277
278type cherrySingleton struct{}
279
280func (p *cherrySingleton) GenerateBuildActions(ctx android.SingletonContext) {
281 cherryRule := ctx.Rule(pctx, "cherry",
282 blueprint.RuleParams{
283 Command: "echo CHERRY IS " + ctx.Config().Getenv("CHERRY") + " > ${out}",
284 CommandDeps: []string{},
285 Description: "Cherry",
286 })
287
288 outputFile := android.PathForOutput(ctx, "cherry", "cherry.txt")
289 var deps android.Paths
290
291 ctx.Build(pctx, android.BuildParams{
292 Rule: cherryRule,
293 Output: outputFile,
294 Inputs: deps,
295 })
296}
297EOF
298
299 export CHERRY=TASTY
300 run_soong
301 grep -q "CHERRY IS TASTY" out/soong/build.ninja \
302 || fail "first value of environment variable is not used"
303
304 export CHERRY=RED
305 run_soong
306 grep -q "CHERRY IS RED" out/soong/build.ninja \
307 || fail "second value of environment variable not used"
308 local mtime1=$(stat -c "%y" out/soong/build.ninja)
309
310 run_soong
311 local mtime2=$(stat -c "%y" out/soong/build.ninja)
312 if [[ "$mtime1" != "$mtime2" ]]; then
313 fail "Output Ninja file changed when environment variable did not"
314 fi
315
316}
317
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100318function test_add_file_to_soong_build() {
319 setup
320 run_soong
321 local mtime1=$(stat -c "%y" out/soong/build.ninja)
322
323 mkdir -p a
324 cat > a/Android.bp <<'EOF'
325bootstrap_go_package {
326 name: "picard-soong-rules",
327 pkgPath: "android/soong/picard",
328 deps: [
329 "blueprint",
330 "soong",
331 "soong-android",
332 ],
333 srcs: [
334 "picard.go",
335 ],
336 pluginFor: ["soong_build"],
337}
338EOF
339
340 cat > a/picard.go <<'EOF'
341package picard
342
343import (
344 "android/soong/android"
345 "github.com/google/blueprint"
346)
347
348var (
349 pctx = android.NewPackageContext("picard")
350)
351
352func init() {
353 android.RegisterSingletonType("picard", PicardSingleton)
354}
355
356func PicardSingleton() android.Singleton {
357 return &picardSingleton{}
358}
359
360type picardSingleton struct{}
361
362func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
363 picardRule := ctx.Rule(pctx, "picard",
364 blueprint.RuleParams{
365 Command: "echo Make it so. > ${out}",
366 CommandDeps: []string{},
367 Description: "Something quotable",
368 })
369
370 outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
371 var deps android.Paths
372
373 ctx.Build(pctx, android.BuildParams{
374 Rule: picardRule,
375 Output: outputFile,
376 Inputs: deps,
377 })
378}
379
380EOF
381
382 run_soong
383 local mtime2=$(stat -c "%y" out/soong/build.ninja)
384 if [[ "$mtime1" == "$mtime2" ]]; then
385 fail "Output Ninja file did not change"
386 fi
387
388 grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
389}
390
Lukacs T. Berkif0b3b942021-03-23 11:46:47 +0100391function test_null_build_after_docs {
392 setup
393 run_soong
394 local mtime1=$(stat -c "%y" out/soong/build.ninja)
395
396 prebuilts/build-tools/linux-x86/bin/ninja -f out/soong/build.ninja soong_docs
397 run_soong
398 local mtime2=$(stat -c "%y" out/soong/build.ninja)
399
400 if [[ "$mtime1" != "$mtime2" ]]; then
401 fail "Output Ninja file changed on null build"
402 fi
403}
404
Lukacs T. Berki97bb9f12021-04-01 18:28:45 +0200405function test_dump_json_module_graph() {
406 setup
407 SOONG_DUMP_JSON_MODULE_GRAPH="$MOCK_TOP/modules.json" run_soong
408 if [[ ! -r "$MOCK_TOP/modules.json" ]]; then
409 fail "JSON file was not created"
410 fi
411}
412
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100413test_bazel_smoke
414test_smoke
415test_null_build
Lukacs T. Berkif0b3b942021-03-23 11:46:47 +0100416test_null_build_after_docs
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100417test_soong_build_rebuilt_if_blueprint_changes
418test_add_file_to_glob
419test_add_android_bp
420test_change_android_bp
421test_delete_android_bp
422test_add_file_to_soong_build
Lukacs T. Berkif0b3b942021-03-23 11:46:47 +0100423test_soong_build_rerun_iff_environment_changes
Lukacs T. Berki97bb9f12021-04-01 18:28:45 +0200424test_dump_json_module_graph