Organize Soong's integration tests:

- Move them into a new directory
- Split tests by theme and add a library file
- Add a shell script that runs them all

Test: Manually ran build/soong/run_integration_tests.sh .
Change-Id: I758b91d679f41aee47d15472cc02547ce89f6386
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
new file mode 100755
index 0000000..b2f7b2b
--- /dev/null
+++ b/tests/bootstrap_test.sh
@@ -0,0 +1,330 @@
+#!/bin/bash -eu
+
+# This test exercises the bootstrapping process of the build system
+# in a source tree that only contains enough files for Bazel and Soong to work.
+
+source "$(dirname "$0")/lib.sh"
+
+function test_smoke {
+  setup
+  run_soong
+}
+
+function test_null_build() {
+  setup
+  run_soong
+  local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+  local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
+  run_soong
+  local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+  local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
+
+  if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
+    # Bootstrapping is always done. It doesn't take a measurable amount of time.
+    fail "Bootstrap Ninja file did not change on null build"
+  fi
+
+  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
+    fail "Output Ninja file changed on null build"
+  fi
+}
+
+function test_soong_build_rebuilt_if_blueprint_changes() {
+  setup
+  run_soong
+  local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+
+  sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
+
+  run_soong
+  local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+
+  if [[ "$mtime1" == "$mtime2" ]]; then
+    fail "Bootstrap Ninja file did not change"
+  fi
+}
+
+function test_change_android_bp() {
+  setup
+  mkdir -p a
+  cat > a/Android.bp <<'EOF'
+python_binary_host {
+  name: "my_little_binary_host",
+  srcs: ["my_little_binary_host.py"]
+}
+EOF
+  touch a/my_little_binary_host.py
+  run_soong
+
+  grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
+
+  cat > a/Android.bp <<'EOF'
+python_binary_host {
+  name: "my_great_binary_host",
+  srcs: ["my_great_binary_host.py"]
+}
+EOF
+  touch a/my_great_binary_host.py
+  run_soong
+
+  grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
+  grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
+}
+
+
+function test_add_android_bp() {
+  setup
+  run_soong
+  local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+  mkdir -p a
+  cat > a/Android.bp <<'EOF'
+python_binary_host {
+  name: "my_little_binary_host",
+  srcs: ["my_little_binary_host.py"]
+}
+EOF
+  touch a/my_little_binary_host.py
+  run_soong
+
+  local mtime2=$(stat -c "%y" out/soong/build.ninja)
+  if [[ "$mtime1" == "$mtime2" ]]; then
+    fail "Output Ninja file did not change"
+  fi
+
+  grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
+
+  run_soong
+}
+
+function test_delete_android_bp() {
+  setup
+  mkdir -p a
+  cat > a/Android.bp <<'EOF'
+python_binary_host {
+  name: "my_little_binary_host",
+  srcs: ["my_little_binary_host.py"]
+}
+EOF
+  touch a/my_little_binary_host.py
+  run_soong
+
+  grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
+
+  rm a/Android.bp
+  run_soong
+
+  grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja && fail "Old module in output"
+}
+
+function test_add_file_to_glob() {
+  setup
+
+  mkdir -p a
+  cat > a/Android.bp <<'EOF'
+python_binary_host {
+  name: "my_little_binary_host",
+  srcs: ["*.py"],
+}
+EOF
+  touch a/my_little_binary_host.py
+  run_soong
+  local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+  touch a/my_little_library.py
+  run_soong
+
+  local mtime2=$(stat -c "%y" out/soong/build.ninja)
+  if [[ "$mtime1" == "$mtime2" ]]; then
+    fail "Output Ninja file did not change"
+  fi
+
+  grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
+}
+
+function test_soong_build_rerun_iff_environment_changes() {
+  setup
+
+  mkdir -p cherry
+  cat > cherry/Android.bp <<'EOF'
+bootstrap_go_package {
+  name: "cherry",
+  pkgPath: "android/soong/cherry",
+  deps: [
+    "blueprint",
+    "soong",
+    "soong-android",
+  ],
+  srcs: [
+    "cherry.go",
+  ],
+  pluginFor: ["soong_build"],
+}
+EOF
+
+  cat > cherry/cherry.go <<'EOF'
+package cherry
+
+import (
+  "android/soong/android"
+  "github.com/google/blueprint"
+)
+
+var (
+  pctx = android.NewPackageContext("cherry")
+)
+
+func init() {
+  android.RegisterSingletonType("cherry", CherrySingleton)
+}
+
+func CherrySingleton() android.Singleton {
+  return &cherrySingleton{}
+}
+
+type cherrySingleton struct{}
+
+func (p *cherrySingleton) GenerateBuildActions(ctx android.SingletonContext) {
+  cherryRule := ctx.Rule(pctx, "cherry",
+    blueprint.RuleParams{
+      Command: "echo CHERRY IS " + ctx.Config().Getenv("CHERRY") + " > ${out}",
+      CommandDeps: []string{},
+      Description: "Cherry",
+    })
+
+  outputFile := android.PathForOutput(ctx, "cherry", "cherry.txt")
+  var deps android.Paths
+
+  ctx.Build(pctx, android.BuildParams{
+    Rule: cherryRule,
+    Output: outputFile,
+    Inputs: deps,
+  })
+}
+EOF
+
+  export CHERRY=TASTY
+  run_soong
+  grep -q "CHERRY IS TASTY" out/soong/build.ninja \
+    || fail "first value of environment variable is not used"
+
+  export CHERRY=RED
+  run_soong
+  grep -q "CHERRY IS RED" out/soong/build.ninja \
+    || fail "second value of environment variable not used"
+  local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+  run_soong
+  local mtime2=$(stat -c "%y" out/soong/build.ninja)
+  if [[ "$mtime1" != "$mtime2" ]]; then
+    fail "Output Ninja file changed when environment variable did not"
+  fi
+
+}
+
+function test_add_file_to_soong_build() {
+  setup
+  run_soong
+  local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+  mkdir -p a
+  cat > a/Android.bp <<'EOF'
+bootstrap_go_package {
+  name: "picard-soong-rules",
+  pkgPath: "android/soong/picard",
+  deps: [
+    "blueprint",
+    "soong",
+    "soong-android",
+  ],
+  srcs: [
+    "picard.go",
+  ],
+  pluginFor: ["soong_build"],
+}
+EOF
+
+  cat > a/picard.go <<'EOF'
+package picard
+
+import (
+  "android/soong/android"
+  "github.com/google/blueprint"
+)
+
+var (
+  pctx = android.NewPackageContext("picard")
+)
+
+func init() {
+  android.RegisterSingletonType("picard", PicardSingleton)
+}
+
+func PicardSingleton() android.Singleton {
+  return &picardSingleton{}
+}
+
+type picardSingleton struct{}
+
+func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+  picardRule := ctx.Rule(pctx, "picard",
+    blueprint.RuleParams{
+      Command: "echo Make it so. > ${out}",
+      CommandDeps: []string{},
+      Description: "Something quotable",
+    })
+
+  outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
+  var deps android.Paths
+
+  ctx.Build(pctx, android.BuildParams{
+    Rule: picardRule,
+    Output: outputFile,
+    Inputs: deps,
+  })
+}
+
+EOF
+
+  run_soong
+  local mtime2=$(stat -c "%y" out/soong/build.ninja)
+  if [[ "$mtime1" == "$mtime2" ]]; then
+    fail "Output Ninja file did not change"
+  fi
+
+  grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
+}
+
+function test_null_build_after_docs {
+  setup
+  run_soong
+  local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+  prebuilts/build-tools/linux-x86/bin/ninja -f out/soong/build.ninja soong_docs
+  run_soong
+  local mtime2=$(stat -c "%y" out/soong/build.ninja)
+
+  if [[ "$mtime1" != "$mtime2" ]]; then
+    fail "Output Ninja file changed on null build"
+  fi
+}
+
+function test_dump_json_module_graph() {
+  setup
+  SOONG_DUMP_JSON_MODULE_GRAPH="$MOCK_TOP/modules.json" run_soong
+  if [[ ! -r "$MOCK_TOP/modules.json" ]]; then
+    fail "JSON file was not created"
+  fi
+}
+
+test_smoke
+test_null_build
+test_null_build_after_docs
+test_soong_build_rebuilt_if_blueprint_changes
+test_add_file_to_glob
+test_add_android_bp
+test_change_android_bp
+test_delete_android_bp
+test_add_file_to_soong_build
+test_soong_build_rerun_iff_environment_changes
+test_dump_json_module_graph