xref: /aosp_15_r20/build/bazel/ci/determinism_test.sh (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
1#!/bin/bash -eu
2
3# Copyright (C) 2023 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17
18# Verifies that various intermediate outputs of the build have deterministic
19# outputs. Nondeterministic intermediate outputs have incremental performance
20# implications, so this is a critical test even if the determinism if the final
21# outputs is not in question.
22#
23# Determinism is verified by running several builds and comparing checksums of
24# outputs. This may provides confidence in determinism, but does not guarantee
25# it. "Flakiness" in this test should thus be treated as indicative of a
26# failure, and investigated promptly.
27if [[ -z ${OUT_DIR+x} ]]; then
28  OUT_DIR="out"
29fi
30
31if [[ -z ${DIST_DIR+x} ]]; then
32  echo "DIST_DIR not set. Using ${OUT_DIR}/dist. This should only be used for manual developer testing."
33  DIST_DIR="${OUT_DIR}/dist"
34fi
35
36if [[ -z ${TARGET_PRODUCT+x} ]]; then
37  echo "TARGET_PRODUCT not set. Using aosp_arm64"
38  TARGET_PRODUCT=aosp_arm64
39fi
40
41if [[ -z ${TARGET_BUILD_VARIANT+x} ]]; then
42  echo "TARGET_BUILD_VARIANT not set. Using userdebug"
43  TARGET_BUILD_VARIANT=userdebug
44fi
45
46UNAME="$(uname)"
47case "$UNAME" in
48Linux)
49  PREBUILTS="prebuilts/build-tools/path/linux-x86"
50  ;;
51Darwin)
52  PREBUILTS="prebuilts/build-tools/path/darwin-x86"
53  ;;
54*)
55  exit 1
56  ;;
57esac
58
59function clean_build {
60  build/soong/soong_ui.bash --make-mode clean
61
62  # Generate the ninja file with default setting. We expect Bazel to be enabled by
63  # default.
64  build/soong/soong_ui.bash --make-mode \
65    --mk-metrics \
66    BAZEL_STARTUP_ARGS="--max_idle_secs=5" \
67    BAZEL_BUILD_ARGS="--color=no --curses=no --show_progress_rate_limit=5" \
68    TARGET_PRODUCT=${TARGET_PRODUCT} \
69    TARGET_BUILD_VARIANT=${TARGET_BUILD_VARIANT} \
70    nothing \
71    dist DIST_DIR=$DIST_DIR
72}
73
74function save_hash {
75  local -r filepath="$1"
76  find $OUT_DIR/soong/workspace -type f,l -iname "BUILD.bazel" -o -iname "*.bzl" | xargs "${PREBUILTS}"/md5sum > $filepath
77  find $OUT_DIR/soong/soong_injection -type f,l | xargs "${PREBUILTS}"/md5sum >> $filepath
78  "${PREBUILTS}"/md5sum $OUT_DIR/soong/Android-${TARGET_PRODUCT}.mk >> $filepath
79  if [[ -z ${SKIP_NINJA_CHECK+x} ]]; then
80    "${PREBUILTS}"/md5sum $OUT_DIR/soong/build.${TARGET_PRODUCT}.ninja >> $filepath
81  fi
82}
83
84TESTDIR=$(mktemp -t testdir.XXXXXX -d)
85FIRST_FILE=$TESTDIR/first_hashes
86TEST_FILE=$TESTDIR/hashes_to_test
87
88clean_build
89save_hash $FIRST_FILE
90
91for i in {1..4} ; do
92  clean_build
93  save_hash $TEST_FILE
94  if cmp -s "$FIRST_FILE" "$TEST_FILE"
95  then
96    echo "Comparison $i succeeded."
97  else
98    cp $FIRST_FILE $TEST_FILE $DIST_DIR
99    >&2 echo "Comparison $i failed. This likely indicates nondeterminism in the differing files."
100    >&2 echo "\n\nFirst file hashes:\n"
101    >&2 cat $FIRST_FILE
102    >&2 echo "\n\nRerun $i:\n"
103    >&2 cat $TEST_FILE
104    exit 1
105  fi
106done
107