android: add the Android KUnit test (#563)

with the tests.zip package provided, which is generated
by the normal gki kernel build

Signed-off-by: Yongqin Liu <yongqin.liu@linaro.org>
diff --git a/automated/android/kunit/kunit.sh b/automated/android/kunit/kunit.sh
new file mode 100755
index 0000000..e958018
--- /dev/null
+++ b/automated/android/kunit/kunit.sh
@@ -0,0 +1,146 @@
+#!/bin/bash -ex
+
+# shellcheck disable=SC1091
+. ../../lib/sh-test-lib
+DIR_OUTPUT="$(pwd)/output"
+mkdir -p "${DIR_OUTPUT}"
+RESULT_FILE="${DIR_OUTPUT}/result.txt"
+export RESULT_FILE
+
+# shellcheck disable=SC1091
+. ../../lib/android-test-lib
+
+RETRY_COUNT=5
+RETRY_INTERVAL=2
+
+TESTS_ZIP_URL=""
+SQUAD_UPLOAD_URL=""
+TRADEFED_PREBUILTS_GIT_URL="https://android.googlesource.com/platform/tools/tradefederation/prebuilts"
+
+F_TESTS_ZIP="$(pwd)/tests.zip"
+DIR_TESTS="$(pwd)/tests"
+DIR_TEST_LOGS="${DIR_OUTPUT}/test-logs"
+F_KUNIT_LOG="${DIR_TEST_LOGS}/kunit.log"
+DIR_TF_PREBUILTS="$(pwd)/prebuilts"
+
+function usage(){
+    echo "Usage: $0 -u <TESTS_ZIP_URL> [ -s <SQUAD_UPLOAD_URL>]" 1>&2
+    exit 1
+}
+
+function upload_logs_to_squad(){
+    if [ -z "${SQUAD_UPLOAD_URL}" ]; then
+        return
+    fi
+    # Upload test log and result files to artifactorial.
+    name_dir_output=$(basename "${DIR_OUTPUT}")
+    if ! tar caf "kunit-output-$(date +%Y%m%d%H%M%S).tar.xz" "${name_dir_output}"; then
+         error_fatal "tradefed - failed to collect results and log files [$ANDROID_SERIAL]"
+    fi
+    ATTACHMENT=$(ls kunit-output-*.tar.xz)
+    ../../utils/upload-to-squad.sh -a "${ATTACHMENT}" -u "${SQUAD_UPLOAD_URL}"
+}
+
+function parse_kunit_log(){
+    local f_kunit_log="${1}"
+    local f_kunit_stub_log="${DIR_TEST_LOGS}/kunit_stub.log"
+
+    if [ -z "${f_kunit_log}" ] || [ ! -f "${f_kunit_log}" ]; then
+        echo "KUnit log does not exist"
+        return
+    fi
+    # grep the stub log to a single file and parsing the results
+    # 20:43:20 stub: soc-utils-test.soc-utils#test_snd_soc_params_to_bclk: PASSED (0ms)
+    # 00:21:09 stub: kunit-example-test.example_init#example_init_test: PASSED (0ms)
+    #  | cut -d: -f4- \            # kunit-example-test.example_init#example_init_test: PASSED (0ms)
+    #  | tr -d ':' \               # kunit-example-test.example_init#example_init_test PASSED (0ms)
+    #  | awk '{print $1, $2}' \    # kunit-example-test.example_init#example_init_test PASSED
+    #  | sort | uniq \             # to filter out the duplication of FAILURE in Result Summary part
+    grep "stub:" "${f_kunit_log}" \
+        | cut -d: -f4- \
+        | tr -d ':' \
+        | awk '{print $1, $2}' \
+        | sort | uniq \
+        > "${f_kunit_stub_log}"
+    while read -r line; do
+        # kunit-example-test.example_init#example_init_test PASSED
+        # kunit-example-test.example#example_skip_test IGNORED
+        # soc-utils-test#soc-utils-test FAILURE
+        test_case_name=$(echo "${line}"|awk '{print $1}')
+        test_case_result=$(echo "${line}"|awk '{print $2}')
+
+        # reformat the test case name to avoid potential confusions
+        # being caused by some special characters
+        test_case_name=$(echo "${test_case_name}" \
+                            | tr -c '#@/+,[:alnum:]:.-' '_' \
+                            | tr -s '_' \
+                            | sed 's/_$//' \
+                            )
+
+        case "X${test_case_result}" in
+            "XPASSED")
+                report_pass "${test_case_name}"
+                ;;
+            "XIGNORED")
+                report_skip "${test_case_name}"
+                ;;
+            "XFAILURE")
+                report_fail "${test_case_name}"
+                ;;
+            *)
+                report_unknown "${test_case_name}"
+                ;;
+        esac
+    done < "${f_kunit_stub_log}"
+}
+
+while getopts "u:s:h" o; do
+  case "$o" in
+    u) TESTS_ZIP_URL="${OPTARG}" ;;
+    s) SQUAD_UPLOAD_URL="${OPTARG}" ;;
+    h|*) usage ;;
+  esac
+done
+
+# export ANDROID_SERIAL
+initialize_adb
+
+if [ -z "${TESTS_ZIP_URL}" ]; then
+    echo "The TESTS_ZIP_URL must be specified."
+    exit 1
+fi
+
+# download and unzip tests.zip
+rm -f "${F_TESTS_ZIP}" && \
+    curl --retry "${RETRY_COUNT}" --retry-delay "${RETRY_INTERVAL}" -fsSL "${TESTS_ZIP_URL}" -o "${F_TESTS_ZIP}"
+rm -fr "${DIR_TESTS}" && \
+    mkdir -p "${DIR_TESTS}" && \
+    unzip -o "${F_TESTS_ZIP}" -d "${DIR_TESTS}"
+
+# clone the tradefed prebuilts repository
+i=1
+while [ $i -le "${RETRY_COUNT}" ]; do
+    rm -fr "${DIR_TF_PREBUILTS}"
+    if git clone --depth 1 "${TRADEFED_PREBUILTS_GIT_URL}" "${DIR_TF_PREBUILTS}"; then
+        break
+    fi
+
+    # try again in ${RETRY_INTERVAL} seconds
+    sleep "${RETRY_INTERVAL}"
+    i=$((i + 1))
+done
+
+# run the kunit test
+mkdir -p "${DIR_TEST_LOGS}"
+prebuilts/filegroups/tradefed/tradefed.sh  \
+    run commandAndExit \
+    template/local_min \
+    --template:map test=suite/test_mapping_suite \
+    --include-filter kunit \
+    --tests-dir="${DIR_TESTS}"  \
+    --log-file-path="${DIR_TEST_LOGS}" \
+    -s "${ANDROID_SERIAL}" |& tee "${F_KUNIT_LOG}"
+
+parse_kunit_log "${F_KUNIT_LOG}"
+
+upload_logs_to_squad
diff --git a/automated/android/kunit/kunit.yaml b/automated/android/kunit/kunit.yaml
new file mode 100644
index 0000000..a38f060
--- /dev/null
+++ b/automated/android/kunit/kunit.yaml
@@ -0,0 +1,34 @@
+metadata:
+    name: kunit-tests
+    format: "Lava-Test Test Definition 1.0"
+    description: |
+        Run the KUnit test on Android based on the tradefed framework
+        provided by google.
+    maintainer:
+        - yongqin.liu@linaro.org
+    os:
+        - android
+    devices:
+        - db845c
+        - rb5
+        - sm8550
+    scope:
+        - functional
+
+params:
+    # The url of the tests.zip file generated during the kernel build,
+    # which includes files for the kunit modules and necessary configurations
+    TESTS_ZIP_URL: ""
+    # The SQUAD url to be used to upload the result and log files.
+    # see https://squad.readthedocs.io/en/latest/intro.html#submitting-results.
+    # SQUAD_ARCHIVE_SUBMIT_TOKEN is used for uploading authentication,
+    # and must be defined by the submitter as one profile managed token
+    SQUAD_UPLOAD_URL: ""
+
+run:
+    steps:
+        - cd ./automated/android/kunit
+        # Run setup.sh in the original shell to reserve env variables.
+        - ./kunit.sh -u "${TESTS_ZIP_URL}" -s "${SQUAD_UPLOAD_URL}"
+        # Send test result to LAVA.
+        - ../../utils/send-to-lava.sh ./output/result.txt