aboutsummaryrefslogtreecommitdiff
path: root/ci/determinism_test.sh
blob: 622bc0e33b1425b495c6e92b2fd85231c3f04b47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/bin/bash -eu

# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


# Verifies that various intermediate outputs of the build have deterministic
# outputs. Nondeterministic intermediate outputs have incremental performance
# implications, so this is a critical test even if the determinism if the final
# outputs is not in question.
#
# Determinism is verified by running several builds and comparing checksums of
# outputs. This may provides confidence in determinism, but does not guarantee
# it. "Flakiness" in this test should thus be treated as indicative of a
# failure, and investigated promptly.
if [[ -z ${OUT_DIR+x} ]]; then
  OUT_DIR="out"
fi

if [[ -z ${DIST_DIR+x} ]]; then
  echo "DIST_DIR not set. Using ${OUT_DIR}/dist. This should only be used for manual developer testing."
  DIST_DIR="${OUT_DIR}/dist"
fi

if [[ -z ${TARGET_PRODUCT+x} ]]; then
  echo "TARGET_PRODUCT not set. Using aosp_arm64"
  TARGET_PRODUCT=aosp_arm64
fi

if [[ -z ${TARGET_BUILD_VARIANT+x} ]]; then
  echo "TARGET_BUILD_VARIANT not set. Using userdebug"
  TARGET_BUILD_VARIANT=userdebug
fi

UNAME="$(uname)"
case "$UNAME" in
Linux)
  PREBUILTS="prebuilts/build-tools/path/linux-x86"
  ;;
Darwin)
  PREBUILTS="prebuilts/build-tools/path/darwin-x86"
  ;;
*)
  exit 1
  ;;
esac

function clean_build {
  build/soong/soong_ui.bash --make-mode clean

  # Generate the ninja file with default setting. We expect Bazel to be enabled by
  # default.
  build/soong/soong_ui.bash --make-mode \
    --mk-metrics \
    BAZEL_STARTUP_ARGS="--max_idle_secs=5" \
    BAZEL_BUILD_ARGS="--color=no --curses=no --show_progress_rate_limit=5" \
    TARGET_PRODUCT=${TARGET_PRODUCT} \
    TARGET_BUILD_VARIANT=${TARGET_BUILD_VARIANT} \
    nothing \
    dist DIST_DIR=$DIST_DIR
}

function save_hash {
  local -r filepath="$1"
  find $OUT_DIR/soong/workspace -type f,l -iname "BUILD.bazel" -o -iname "*.bzl" | xargs "${PREBUILTS}"/md5sum > $filepath
  find $OUT_DIR/soong/soong_injection -type f,l | xargs "${PREBUILTS}"/md5sum >> $filepath
  "${PREBUILTS}"/md5sum $OUT_DIR/soong/Android-${TARGET_PRODUCT}.mk >> $filepath
  if [[ -z ${SKIP_NINJA_CHECK+x} ]]; then
    "${PREBUILTS}"/md5sum $OUT_DIR/soong/build.ninja >> $filepath
  fi
}

TESTDIR=$(mktemp -t testdir.XXXXXX -d)
FIRST_FILE=$TESTDIR/first_hashes
TEST_FILE=$TESTDIR/hashes_to_test

clean_build
save_hash $FIRST_FILE

for i in {1..4} ; do
  clean_build
  save_hash $TEST_FILE
  if cmp -s "$FIRST_FILE" "$TEST_FILE"
  then
    echo "Comparison $i succeeded."
  else
    cp $FIRST_FILE $TEST_FILE $DIST_DIR
    >&2 echo "Comparison $i failed. This likely indicates nondeterminism in the differing files."
    >&2 echo "\n\nFirst file hashes:\n"
    >&2 cat $FIRST_FILE
    >&2 echo "\n\nRerun $i:\n"
    >&2 cat $TEST_FILE
    exit 1
  fi
done