From ed8d2d30e7d298fa05395a79cc3502240d9c0721 Mon Sep 17 00:00:00 2001
From: DCCooper <1866858@gmail.com>
Date: Mon, 1 Nov 2021 16:24:14 +0800
Subject: [PATCH 13/16] test:cleancode test for better experience

change:
1. shellcheck fix for scripts in used hack
2. use busyobx instead of openeuler base image to speed up test
3. add test-unit-cover, test-sdv-cover, test-cover for project to
   generate coverage files

Signed-off-by: DCCooper <1866858@gmail.com>
---
 Makefile                                   |  18 ++++
 hack/all_coverage.sh                       |  26 ++++++
 hack/merge_coverage.sh                     |  55 +++++++++++
 hack/sdv_coverage.sh                       | 104 +++++++++++++++++++++
 hack/unit_test.sh                          |  82 +++++++++++-----
 tests/src/integration_test_set_new_root.sh |   7 +-
 6 files changed, 268 insertions(+), 24 deletions(-)
 create mode 100755 hack/all_coverage.sh
 create mode 100644 hack/merge_coverage.sh
 create mode 100755 hack/sdv_coverage.sh

diff --git a/Makefile b/Makefile
index d41a9fdb..73482a41 100644
--- a/Makefile
+++ b/Makefile
@@ -112,6 +112,24 @@ test-integration: ## Test integration case
 	@./tests/test.sh integration
 	@echo "Integration test done!"
 
+.PHONY: test-unit-cover
+test-unit-cover: ## Test unit case and generate coverage
+	@echo "Unit test cover starting..."
+	@./hack/unit_test.sh cover
+	@echo "Unit test cover done!"
+
+.PHONY: test-sdv-cover
+test-sdv-cover: ## Test integration case and generate coverage
+	@echo "Integration test cover starting..."
+	@./hack/sdv_coverage.sh
+	@echo "Integration test cover done!"
+
+.PHONY: test-cover
+test-cover: test-sdv-cover test-unit-cover ## Test both unit and sdv case and generate unity coverage
+	@echo "Test cover starting..."
+	@./hack/all_coverage.sh
+	@echo "Test cover done!"
+
 ##@ Development
 
 .PHONY: build-image
diff --git a/hack/all_coverage.sh b/hack/all_coverage.sh
new file mode 100755
index 00000000..9f9eb5ff
--- /dev/null
+++ b/hack/all_coverage.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
+# isula-build licensed under the Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+#     http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+# PURPOSE.
+# See the Mulan PSL v2 for more details.
+# Author: Xiang Li
+# Create: 2020-03-01
+# Description: shell script for all coverage
+# Note: use this file by typing make test-cover
+#       Do not run this script directly
+
+SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" || exit; pwd)
+# shellcheck disable=SC1091
+source "${SCRIPT_DIR}"/merge_coverage.sh
+
+unit_coverage=${PWD}/cover_unit_test_all.out
+sdv_coverage=${PWD}/cover_sdv_test_all.out
+output_file=${PWD}/cover_test_all
+
+merge_cover "${output_file}" "${sdv_coverage}" "${unit_coverage}"
diff --git a/hack/merge_coverage.sh b/hack/merge_coverage.sh
new file mode 100644
index 00000000..6e529a34
--- /dev/null
+++ b/hack/merge_coverage.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+# Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
+# isula-build licensed under the Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+#     http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+# PURPOSE.
+# See the Mulan PSL v2 for more details.
+# Author: Xiang Li
+# Create: 2021-11-01
+# Description: merge coverage from input coverage files
+# Note: Do not run this script directly
+
+# Usage: merge_cover outputfile file1 file2 ... fileN
+# Input: first: outputfile name
+#        remaining: coverage files
+function merge_cover() {
+    output_file_name="$1"
+    input_coverages=( "${@:2}" )
+
+    output_coverage_file=${output_file_name}.out
+    output_html_file=${output_file_name}.html
+    output_merge_cover=${output_file_name}.merge
+    grep -r -h -v "^mode:" "${input_coverages[@]}" | sort > "$output_merge_cover"
+    current=""
+    count=0
+    echo "mode: set" > "$output_coverage_file"
+    # read the cover report from merge_cover, convert it, write to final coverage
+    while read -r line; do
+        block=$(echo "$line" | cut -d ' ' -f1-2)
+        num=$(echo "$line" | cut -d ' ' -f3)
+        if [ "$current" == "" ]; then
+            current=$block
+            count=$num
+        elif [ "$block" == "$current" ]; then
+            count=$((count + num))
+        else
+            # if the sorted two lines are not in the same code block, write the statics result of last code block to the final coverage
+            echo "$current" $count >> "${output_coverage_file}"
+            current=$block
+            count=$num
+        fi
+    done < "$output_merge_cover"
+    rm -rf "${output_merge_cover}"
+
+    # merge the results of last line to the final coverage
+    if [ "$current" != "" ]; then
+        echo "$current" "$count" >> "${output_coverage_file}"
+    fi
+
+    go tool cover -html="${output_coverage_file}" -o "$output_html_file"
+}
diff --git a/hack/sdv_coverage.sh b/hack/sdv_coverage.sh
new file mode 100755
index 00000000..874d9373
--- /dev/null
+++ b/hack/sdv_coverage.sh
@@ -0,0 +1,104 @@
+#!/bin/bash
+
+# Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
+# isula-build licensed under the Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+#     http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+# PURPOSE.
+# See the Mulan PSL v2 for more details.
+# Author: Xiang Li
+# Create: 2020-03-01
+# Description: shell script for coverage
+# Note: use this file by typing make test-sdv-cover or make test-cover
+#       Do not run this script directly
+
+project_root=${PWD}
+vendor_name="isula.org"
+project_name="isula-build"
+main_relative_path="cmd/daemon"
+exclude_pattern="gopkgs|api/services"
+go_test_mod_method="-mod=vendor"
+go_test_count_method="-count=1"
+go_test_cover_method="-covermode=set"
+main_pkg="${vendor_name}/${project_name}/${main_relative_path}"
+main_test_file=${project_root}/${main_relative_path}/main_test.go
+main_file=${project_root}/${main_relative_path}/main.go
+coverage_file=${project_root}/cover_sdv_test_all.out
+coverage_html=${project_root}/cover_sdv_test_all.html
+coverage_log=${project_root}/cover_sdv_test_all.log
+main_test_binary_file=${project_root}/main.test
+
+function precheck() {
+    if pgrep isula-builder > /dev/null 2>&1; then
+        echo "isula-builder is already running, please stop it first"
+        exit 1
+    fi
+}
+
+function modify_main_test() {
+    # first backup file
+    cp "${main_file}" "${main_file}".bk
+    cp "${main_test_file}" "${main_test_file}".bk
+    # delete Args field for main.go
+    local comment_pattern="Args:  util.NoArgs"
+    sed -i "/$comment_pattern/s/^#*/\/\/ /" "${main_file}"
+    # add new line for main_test.go
+    code_snippet="func TestMain(t *testing.T) { main() }"
+    echo "$code_snippet" >> "${main_test_file}"
+}
+
+function recover_main_test() {
+    mv "${main_file}".bk "${main_file}"
+    mv "${main_test_file}".bk "${main_test_file}"
+}
+
+function build_main_test_binary() {
+    pkgs=$(go list ${go_test_mod_method} "${project_root}"/... | grep -Ev ${exclude_pattern} | tr "\r\n" ",")
+    go test -coverpkg="${pkgs}" ${main_pkg} ${go_test_mod_method} ${go_test_cover_method} ${go_test_count_method} -c -o="${main_test_binary_file}"
+}
+
+function run_main_test_binary() {
+    ${main_test_binary_file} -test.coverprofile="${coverage_file}" > "${coverage_log}" 2>&1 &
+    main_test_pid=$!
+    for _ in $(seq 1 10); do
+        if isula-build info > /dev/null 2>&1; then
+            break
+        else
+            sleep 1
+        fi
+    done
+}
+
+function run_coverage_test() {
+    # do cover tests
+    echo "sdv coverage test"
+    # cover_test_xxx
+    # cover_test_xxx
+    # cover_test_xxx
+    # cover_test_xxx
+}
+
+function finish_coverage_test() {
+    kill -15 $main_test_pid
+}
+
+function generate_coverage() {
+    go tool cover -html="${coverage_file}" -o="${coverage_html}"
+}
+
+function cleanup() {
+    rm "$main_test_binary_file"
+}
+
+precheck
+modify_main_test
+build_main_test_binary
+recover_main_test
+run_main_test_binary
+run_coverage_test
+finish_coverage_test
+generate_coverage
+cleanup
diff --git a/hack/unit_test.sh b/hack/unit_test.sh
index a94a2d38..94a44a95 100755
--- a/hack/unit_test.sh
+++ b/hack/unit_test.sh
@@ -12,32 +12,72 @@
 # Author: iSula Team
 # Create: 2020-07-11
 # Description: go test script
+# Note: use this file by typing make unit-test or make unit-test-cover
+#       Do not run this script directly
+
+SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" || exit; pwd)
+# shellcheck disable=SC1091
+source "${SCRIPT_DIR}"/merge_coverage.sh
 
 export GO111MODULE=on
+run_coverage=$1
+covers_folder=${PWD}/covers
+testlog=${PWD}"/unit_test_log"
+exclude_pattern="gopkgs|api/services"
+go_test_mod_method="-mod=vendor"
+go_test_count_method="-count=1"
+go_test_timeout_flag="-timeout=300s"
+go_test_race_flag="-race"
 
-TEST_ARGS=""
-if [ ! -z "${TEST_REG}" ]; then
-    TEST_ARGS+=" -args TEST_REG=${TEST_REG}"
-fi
-if [ ! -z "${SKIP_REG}" ]; then
-    TEST_ARGS+=" -args SKIP_REG=${SKIP_REG}"
-fi
-echo "Testing with args ${TEST_ARGS}"
+function precheck() {
+    if pgrep isula-builder > /dev/null 2>&1; then
+        echo "isula-builder is already running, please stop it first"
+        exit 1
+    fi
+}
 
-testlog=${PWD}"/unit_test_log"
-rm -f "${testlog}"
-touch "${testlog}"
-golist=$(go list ./... | grep -v gopkgs)
-for path in ${golist}; do
-    echo "Start to test: ${path}"
-    # TEST_ARGS is " -args SKIP_REG=foo", so no double quote for it
-    go test -race -mod=vendor -cover -count=1 -timeout 300s -v "${path}" ${TEST_ARGS} >> "${testlog}"
-    cat "${testlog}" | grep -E -- "--- FAIL:|^FAIL"
-    if [ $? -eq 0 ]; then
+function run_unit_test() {
+    TEST_ARGS=""
+    if [ -n "${TEST_REG}" ]; then
+        TEST_ARGS+=" -args TEST_REG=${TEST_REG}"
+    fi
+    if [ -n "${SKIP_REG}" ]; then
+        TEST_ARGS+=" -args SKIP_REG=${SKIP_REG}"
+    fi
+    echo "Testing with args ${TEST_ARGS}"
+
+    rm -f "${testlog}"
+    if [[ -n $run_coverage ]]; then
+        mkdir -p "${covers_folder}"
+    fi
+    for package in $(go list ${go_test_mod_method} ./... | grep -Ev ${exclude_pattern}); do
+        echo "Start to test: ${package}"
+        if [[ -n $run_coverage ]]; then
+            coverprofile_file="${covers_folder}/$(echo "$package" | tr / -).cover"
+            coverprofile_flag="-coverprofile=${coverprofile_file}"
+            go_test_covermode_flag="-covermode=set"
+            go_test_race_flag=""
+        fi
+        # TEST_ARGS is " -args SKIP_REG=foo", so no double quote for it
+        # shellcheck disable=SC2086
+        go test -v ${go_test_race_flag} ${go_test_mod_method} ${coverprofile_flag} ${go_test_covermode_flag} -coverpkg=${package} ${go_test_count_method} ${go_test_timeout_flag} "${package}" ${TEST_ARGS} >> "${testlog}"
+    done
+
+    if grep -E -- "--- FAIL:|^FAIL" "${testlog}"; then
         echo "Testing failed... Please check ${testlog}"
-        exit 1
     fi
     tail -n 1 "${testlog}"
-done
 
-rm -f "${testlog}"
+    rm -f "${testlog}"
+}
+
+function generate_unit_test_coverage() {
+    if [[ -n ${run_coverage} ]]; then
+        merge_cover "cover_unit_test_all" "${covers_folder}"
+        rm -rf "${covers_folder}"
+    fi
+}
+
+precheck
+run_unit_test
+generate_unit_test_coverage
diff --git a/tests/src/integration_test_set_new_root.sh b/tests/src/integration_test_set_new_root.sh
index bb11a080..ae8d436b 100644
--- a/tests/src/integration_test_set_new_root.sh
+++ b/tests/src/integration_test_set_new_root.sh
@@ -12,6 +12,7 @@
 # Author: Weizheng Xing
 # Create: 2021-05-29
 # Description: test set new run and data root in configuration.toml
+# History: 2021-8-18 Xiang Li <lixiang172@huawei.com> use busyobx instead of openeuler base image to speed up test
 
 top_dir=$(git rev-parse --show-toplevel)
 # shellcheck disable=SC1091
@@ -20,7 +21,7 @@ source "$top_dir"/tests/lib/common.sh
 run_root="/var/run/new-isula-build"
 data_root="/var/lib/new-isula-build"
 config_file="/etc/isula-build/configuration.toml"
-base_image="hub.oepkgs.net/openeuler/openeuler:21.03"
+image="hub.oepkgs.net/openeuler/busybox:latest"
 
 function clean()
 {
@@ -47,10 +48,10 @@ function pre_test()
 function do_test()
 {
     tree_node_befor=$(tree -L 3 $data_root | wc -l)
-    run_with_debug "isula-build ctr-img pull $base_image"
+    run_with_debug "isula-build ctr-img pull $image"
     tree_node_after=$(tree -L 3 $data_root | wc -l)
 
-    if [ $((tree_node_after - tree_node_befor)) -eq 8 ] && run_with_debug "isula-build ctr-img rm $base_image"; then
+    if [ $((tree_node_after - tree_node_befor)) -eq 8 ] && run_with_debug "isula-build ctr-img rm $image"; then
         echo "PASS"
     else
         echo "Sets of run and data root are not effective"
-- 
2.27.0

