556 lines
22 KiB
YAML
556 lines
22 KiB
YAML
# Functional Test is a subset of minikube integration test, testing the most essential features of minikube.
|
|
name: Functional Test
|
|
on:
|
|
workflow_dispatch:
|
|
pull_request:
|
|
paths:
|
|
- "go.mod"
|
|
- "**.go"
|
|
- "Makefile"
|
|
- "!site/**"
|
|
- "!**.md"
|
|
- "!**.json"
|
|
push:
|
|
branches: [ master ]
|
|
paths:
|
|
- "go.mod"
|
|
- "**.go"
|
|
- "Makefile"
|
|
- "!site/**"
|
|
- "!**.md"
|
|
- "!**.json"
|
|
# Limit one functional test job running per PR/Branch
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
# For example, if you push multiple commits to a pull request in quick succession, only the latest workflow run will continue
|
|
cancel-in-progress: true
|
|
env:
|
|
GOPROXY: https://proxy.golang.org
|
|
GO_VERSION: '1.24.6'
|
|
permissions:
|
|
contents: read
|
|
jobs:
|
|
# build-test-binaries job runs before all other jobs and produces binaries/test-data to be shared by all following jobs
|
|
build-test-binaries:
|
|
runs-on: ubuntu-22.04
|
|
steps:
|
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
|
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
|
with:
|
|
go-version: ${{env.GO_VERSION}}
|
|
cache: true
|
|
- name: Download Dependencies
|
|
run: go mod download
|
|
- name: Build minikube and e2e test binaries
|
|
run: |
|
|
make e2e-linux-amd64 e2e-darwin-amd64
|
|
cp -r test/integration/testdata ./out
|
|
- name: Upload Test Binaries
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
with:
|
|
name: binaries
|
|
path: out
|
|
functional-test:
|
|
name: ${{ matrix.name }}
|
|
needs: build-test-binaries
|
|
runs-on: ${{ matrix.os }}
|
|
permissions:
|
|
contents: none
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- name: docker-docker-ubuntu22.04-x86_64
|
|
driver: docker
|
|
cruntime: docker
|
|
os: ubuntu-22.04
|
|
test-timeout: 15m
|
|
- name: docker-containerd-ubuntu-22.04-x86_64
|
|
driver: docker
|
|
cruntime: containerd
|
|
extra-start-args: --container-runtime=containerd
|
|
os: ubuntu-22.04
|
|
test-timeout: 15m
|
|
- name: docker-containerd-rootless-ubuntu-22.04-x86_64
|
|
driver: docker
|
|
cruntime: containerd
|
|
os: ubuntu-22.04
|
|
extra-start-args: --container-runtime=containerd --rootless
|
|
rootless: true
|
|
test-timeout: 15m
|
|
- name: podman-docker-ubuntu-24.04-x86_64
|
|
driver: podman
|
|
cruntime: docker
|
|
os: ubuntu-24.04
|
|
test-timeout: 15m
|
|
- name: baremetal-docker-ubuntu-22.04-x86_64
|
|
driver: none
|
|
cruntime: docker
|
|
os: ubuntu-22.04
|
|
test-timeout: 7m
|
|
- name: qemu-docker-macos-13-x86_64
|
|
driver: qemu
|
|
cruntime: docker
|
|
os: macos-13
|
|
extra-start-args: --network socket_vmnet
|
|
test-timeout: 50m
|
|
- name: vfkit-docker-macos-13-x86_64
|
|
driver: vfkit
|
|
cruntime: docker
|
|
os: macos-13
|
|
extra-start-args: --network vmnet-shared
|
|
test-timeout: 50m
|
|
steps:
|
|
- name: Info Block (macOS)
|
|
if: runner.os == 'macOS'
|
|
shell: bash
|
|
run: |
|
|
set -x
|
|
echo "=== Kernel and OS ==="
|
|
uname -a
|
|
sw_vers
|
|
sysctl kern.osrelease kern.osversion kern.version || true
|
|
|
|
echo "=== CPU ==="
|
|
sysctl -n machdep.cpu.brand_string
|
|
sysctl -n hw.ncpu
|
|
sysctl -n machdep.cpu.core_count || true
|
|
sysctl -n machdep.cpu.thread_count || true
|
|
sysctl -n machdep.cpu.features || true
|
|
sysctl -n machdep.cpu.leaf7_features || true
|
|
sysctl -n machdep.cpu.extfeatures || true
|
|
|
|
echo "=== Memory ==="
|
|
sysctl -n hw.memsize
|
|
echo "$(sysctl -n hw.memsize) / 1024 / 1024 / 1024" | bc
|
|
sysctl -n hw.pagesize || true
|
|
vm_stat || true
|
|
|
|
echo "=== Virtualization ==="
|
|
sysctl -n kern.hv_vmm_present
|
|
sysctl -n kern.hv_support
|
|
sysctl -n machdep.cpu.features | grep -i vmx || true
|
|
|
|
echo "=== Hardware Inventory ==="
|
|
sysctl hw.model
|
|
system_profiler SPHardwareDataType
|
|
|
|
echo "=== Storage ==="
|
|
diskutil list || true
|
|
df -h
|
|
system_profiler SPStorageDataType | sed -n '1,200p' || true
|
|
|
|
echo "=== Network ==="
|
|
ifconfig
|
|
networksetup -listallhardwareports || true
|
|
scutil --get HostName || true
|
|
scutil --get LocalHostName || true
|
|
scutil --get ComputerName || true
|
|
route -n get default || true
|
|
netstat -rn || true
|
|
scutil --dns || true
|
|
|
|
echo "=== Uptime and Load ==="
|
|
uptime
|
|
sysctl kern.boottime || true
|
|
|
|
echo "=== Security ==="
|
|
spctl --status || true
|
|
csrutil status || true
|
|
- name: Info Block (linux)
|
|
if: runner.os == 'Linux'
|
|
shell: bash
|
|
run: |
|
|
set -x
|
|
echo "=== Kernel and OS ==="
|
|
uname -a
|
|
cat /etc/os-release
|
|
|
|
echo "=== CPU ==="
|
|
nproc
|
|
grep -m1 'model name' /proc/cpuinfo || true
|
|
grep -m1 '^flags' /proc/cpuinfo || true
|
|
lscpu || true
|
|
lscpu | grep -i 'hypervisor\|virt' || true
|
|
|
|
echo "=== Memory ==="
|
|
grep MemTotal /proc/meminfo || true
|
|
awk '/MemTotal/ {printf "%.2f\n", $2 / 1024 / 1024}' /proc/meminfo || true
|
|
free -h || true
|
|
|
|
echo "=== Virtualization ==="
|
|
systemd-detect-virt || true
|
|
# CPU virtualization flags present
|
|
egrep -c '(vmx|svm)' /proc/cpuinfo || true
|
|
# KVM modules and nested virtualization status
|
|
lsmod | grep -E '(^kvm|kvm_(intel|amd))' || true
|
|
if [ -f /sys/module/kvm_intel/parameters/nested ]; then
|
|
echo -n "kvm_intel nested: "; cat /sys/module/kvm_intel/parameters/nested
|
|
fi
|
|
if [ -f /sys/module/kvm_amd/parameters/nested ]; then
|
|
echo -n "kvm_amd nested: "; cat /sys/module/kvm_amd/parameters/nested
|
|
fi
|
|
sudo journalctl -k | grep -i kvm | tail -n 100 || true
|
|
if command -v virt-host-validate >/dev/null 2>&1; then
|
|
sudo virt-host-validate || true
|
|
fi
|
|
|
|
echo "=== Hardware Inventory ==="
|
|
sudo dmidecode -s system-manufacturer || true
|
|
sudo dmidecode -s system-product-name || true
|
|
sudo dmidecode -t bios -t system -t processor -t memory | sed -n '1,200p' || true
|
|
sudo lshw -short || true
|
|
lspci -nn || true
|
|
lsusb || true
|
|
|
|
echo "=== Storage ==="
|
|
lsblk -o NAME,MODEL,SIZE,TYPE,MOUNTPOINT,FSTYPE || true
|
|
df -h || true
|
|
|
|
echo "=== Network ==="
|
|
ip addr show || true
|
|
ip route || true
|
|
ip -s link || true
|
|
ifconfig || true
|
|
|
|
echo "=== Cgroups ==="
|
|
stat -fc %T /sys/fs/cgroup || true
|
|
|
|
echo "=== Uptime and Load ==="
|
|
uptime || true
|
|
who -b || true
|
|
cat /proc/loadavg || true
|
|
awk '{printf "Uptime (seconds): %s\n", $1}' /proc/uptime 2>/dev/null || true
|
|
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
|
with:
|
|
go-version: ${{env.GO_VERSION}}
|
|
cache: true
|
|
- name: Install gopogh
|
|
shell: bash
|
|
run: |
|
|
GOPOGH_VERSION=v0.29.0
|
|
GOOS=$(go env GOOS)
|
|
GOARCH=$(go env GOARCH)
|
|
URL="https://github.com/medyagh/gopogh/releases/download/${GOPOGH_VERSION}/gopogh-${GOOS}-${GOARCH}"
|
|
echo "Downloading ${URL}"
|
|
curl -fsSL "${URL}" -o gopogh
|
|
sudo install -m 0755 gopogh /usr/local/bin/gopogh
|
|
rm gopogh
|
|
command -v gopogh
|
|
gopogh -version || true
|
|
- name: Set up cgroup v2 delegation (rootless)
|
|
if: ${{ matrix.rootless }}
|
|
run: |
|
|
sudo mkdir -p /etc/systemd/system/user@.service.d
|
|
cat <<EOF | sudo tee /etc/systemd/system/user@.service.d/delegate.conf
|
|
[Service]
|
|
Delegate=cpu cpuset io memory pids
|
|
EOF
|
|
sudo systemctl daemon-reload
|
|
- name: Set up Rootless Docker (rootless)
|
|
if: ${{ matrix.rootless }}
|
|
run: |
|
|
sudo apt-get remove moby-engine-*
|
|
curl https://get.docker.com | sudo sh
|
|
dockerd-rootless-setuptool.sh install -f
|
|
docker context use rootless
|
|
- name: Ensure bootpd is enabled (macos-13)
|
|
if: matrix.os == 'macos-13'
|
|
shell: bash
|
|
run: |
|
|
set -x
|
|
fw=/usr/libexec/ApplicationFirewall/socketfilterfw
|
|
sudo $fw --remove /usr/libexec/bootpd
|
|
sudo $fw --add /usr/libexec/bootpd
|
|
sudo $fw --unblock /usr/libexec/bootpd
|
|
- name: Update brew package index (macos)
|
|
if: runner.os == 'macOS'
|
|
run: brew update
|
|
- name: Update apt-get package index (ubuntu)
|
|
if: runner.os == 'Linux' && (matrix.driver == 'podman' || matrix.driver == 'none')
|
|
run: sudo apt-get update -qq
|
|
- name: Install cri_dockerd (baremetal only)
|
|
shell: bash
|
|
if: matrix.driver == 'none'
|
|
run: |
|
|
CRI_DOCKERD_VERSION="v0.4.0"
|
|
CRI_DOCKERD_COMMIT="b9b889355f3002c01db294427964e454dfbc3feb"
|
|
CRI_DOCKERD_BASE_URL="https://storage.googleapis.com/kicbase-artifacts/cri-dockerd/${CRI_DOCKERD_COMMIT}"
|
|
sudo curl -L "${CRI_DOCKERD_BASE_URL}/amd64/cri-dockerd" -o /usr/bin/cri-dockerd
|
|
sudo curl -L "${CRI_DOCKERD_BASE_URL}/cri-docker.socket" -o /usr/lib/systemd/system/cri-docker.socket
|
|
sudo curl -L "${CRI_DOCKERD_BASE_URL}/cri-docker.service" -o /usr/lib/systemd/system/cri-docker.service
|
|
sudo chmod +x /usr/bin/cri-dockerd
|
|
- name: Install crictl (baremetal only)
|
|
shell: bash
|
|
if: matrix.driver == 'none'
|
|
run: |
|
|
CRICTL_VERSION="v1.28.0"
|
|
curl -L https://github.com/kubernetes-sigs/cri-tools/releases/download/$CRICTL_VERSION/crictl-${CRICTL_VERSION}-linux-amd64.tar.gz --output crictl-${CRICTL_VERSION}-linux-amd64.tar.gz
|
|
sudo tar zxvf crictl-$CRICTL_VERSION-linux-amd64.tar.gz -C /usr/local/bin
|
|
# conntrack is required for kubernetes 1.18 and higher
|
|
- name: Install conntrack & socat (baremetal only)
|
|
shell: bash
|
|
if: matrix.driver == 'none'
|
|
run: sudo apt-get -qq -y install conntrack
|
|
# socat is required for kubectl port forward which is used in some tests
|
|
- name: Install socat (baremetal only)
|
|
shell: bash
|
|
if: matrix.driver == 'none'
|
|
run: sudo apt-get -qq -y install socat
|
|
- name: Install container networking plugins (baremetal only)
|
|
shell: bash
|
|
if: matrix.driver == 'none'
|
|
run: |
|
|
CNI_PLUGIN_VERSION="v1.7.1"
|
|
CNI_PLUGIN_TAR="cni-plugins-linux-amd64-$CNI_PLUGIN_VERSION.tgz"
|
|
CNI_PLUGIN_INSTALL_DIR="/opt/cni/bin"
|
|
curl -LO "https://github.com/containernetworking/plugins/releases/download/$CNI_PLUGIN_VERSION/$CNI_PLUGIN_TAR"
|
|
sudo mkdir -p "$CNI_PLUGIN_INSTALL_DIR"
|
|
sudo tar -xf "$CNI_PLUGIN_TAR" -C "$CNI_PLUGIN_INSTALL_DIR"
|
|
rm "$CNI_PLUGIN_TAR"
|
|
- name: Install docker-cli
|
|
run: |
|
|
set -x
|
|
if [[ "$RUNNER_OS" == "macOS" ]]; then
|
|
brew install docker
|
|
fi
|
|
echo "=== Docker Version ==="
|
|
docker version || true
|
|
if [[ "$RUNNER_OS" == "Linux" ]]; then
|
|
echo "=== Docker Info ==="
|
|
docker info || true
|
|
|
|
echo "=== Docker Disk Usage ==="
|
|
docker system df || true
|
|
|
|
echo "=== Docker System Info (JSON) ==="
|
|
docker system info --format='{{json .}}' | { command -v jq >/dev/null 2>&1 && jq . || cat; } || true
|
|
|
|
echo "=== Running Containers ==="
|
|
docker ps -a || true
|
|
|
|
echo "=== Images ==="
|
|
docker images || true
|
|
fi
|
|
- name: Install podman
|
|
if: matrix.driver == 'podman'
|
|
shell: bash
|
|
run: |
|
|
sudo apt -q update
|
|
sudo apt install -q -y podman
|
|
lsb_release -a || true
|
|
echo "=== podman version ==="
|
|
podman version || true
|
|
echo "=== podman info ==="
|
|
podman info || true
|
|
echo "=== podman system df ==="
|
|
podman system df || true
|
|
echo "=== podman system info (JSON) ==="
|
|
podman system info --format='{{json .}}' || true
|
|
echo "=== podman ps ==="
|
|
podman ps || true
|
|
- name: Install kubectl
|
|
shell: bash
|
|
run: |
|
|
if [[ "$RUNNER_OS" == "macOS" ]]; then
|
|
brew install kubectl
|
|
elif [[ "$RUNNER_OS" == "Linux" ]]; then
|
|
tmp=$(mktemp)
|
|
curl -fsSL -o "$tmp" "https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
|
sudo install -m 0755 "$tmp" /usr/local/bin/kubectl
|
|
rm "$tmp"
|
|
else
|
|
echo "Unsupported OS: $RUNNER_OS"
|
|
exit 1
|
|
fi
|
|
kubectl version --client=true
|
|
- name: Install qemu and socket_vmnet (macos)
|
|
if: matrix.os == 'macos-13' && matrix.driver == 'qemu'
|
|
run: |
|
|
brew install qemu socket_vmnet
|
|
HOMEBREW=$(which brew) && sudo ${HOMEBREW} services start socket_vmnet
|
|
- name: Install vfkit and vmnet_helper (macos)
|
|
if: matrix.os == 'macos-13' && matrix.driver == 'vfkit'
|
|
run: |
|
|
brew install vfkit
|
|
machine="$(uname -m)"
|
|
archive="vmnet-helper-$machine.tar.gz"
|
|
curl -LOf "https://github.com/nirs/vmnet-helper/releases/latest/download/$archive"
|
|
sudo tar xvf "$archive" -C / opt/vmnet-helper
|
|
sudo install -m 0640 /opt/vmnet-helper/share/doc/vmnet-helper/sudoers.d/vmnet-helper /etc/sudoers.d/
|
|
- name: Download Test Binaries
|
|
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0
|
|
with:
|
|
name: binaries
|
|
- name: Disable AppArmor for MySQL
|
|
if: runner.os == 'Linux'
|
|
run: |
|
|
sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
|
|
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld
|
|
- name: Run Integration Test
|
|
id: run_test
|
|
continue-on-error: true
|
|
shell: bash
|
|
run: |
|
|
set -x
|
|
mkdir -p report
|
|
chmod a+x ./e2e-*
|
|
chmod a+x ./minikube-*
|
|
./minikube-$(go env GOOS)-$(go env GOARCH) delete --all --purge
|
|
START_TIME=$(date -u +%s)
|
|
./e2e-$(go env GOOS)-$(go env GOARCH) -minikube-start-args=" --driver=${{ matrix.driver }} ${{ matrix.extra-start-args }} -v=6 --alsologtostderr" -test.run TestFunctional -test.timeout=${{ matrix.test-timeout }} -test.v -binary=./minikube-$(go env GOOS)-$(go env GOARCH) 2>&1 | tee ./report/testout.txt
|
|
END_TIME=$(date -u +%s)
|
|
TIME_ELAPSED=$(($END_TIME-$START_TIME))
|
|
min=$((${TIME_ELAPSED}/60))
|
|
sec=$((${TIME_ELAPSED}%60))
|
|
TIME_ELAPSED="${min} min $sec seconds "
|
|
# make variables available for next step
|
|
echo "TIME_ELAPSED=${TIME_ELAPSED}" >> $GITHUB_ENV
|
|
- name: Generate Gopogh HTML Report
|
|
if: always()
|
|
shell: bash
|
|
run: |
|
|
# Check if the test step failed AND the log contains "timed out"
|
|
if [[ "${{ steps.run_test.outcome }}" == "failure" && $(grep -c "timed out" ./report/testout.txt) -gt 0 ]]; then
|
|
# If it was a timeout, set your custom message
|
|
RESULT_SHORT="⌛⌛⌛ Test Timed out ${TIME_ELAPSED} ⌛⌛⌛"
|
|
else
|
|
go tool test2json -t < ./report/testout.txt > ./report/testout.json || true
|
|
STAT=$(gopogh -in ./report/testout.json -out_html ./report/testout.html -out_summary ./report/testout_summary.json -name "${{ matrix.name }} ${GITHUB_REF}" -repo "${GITHUB_REPOSITORY}" -details "${GITHUB_SHA}") || true
|
|
PassNum=$(echo $STAT | jq '.NumberOfPass')
|
|
FailNum=$(echo $STAT | jq '.NumberOfFail')
|
|
TestsNum=$(echo $STAT | jq '.NumberOfTests')
|
|
|
|
if [ "${FailNum}" -eq 0 ]; then
|
|
STATUS_ICON="✓"
|
|
else
|
|
STATUS_ICON="✗"
|
|
fi
|
|
if [ "${PassNum}" -eq 0 ]; then
|
|
STATUS_ICON="✗"
|
|
fi
|
|
|
|
# Result in one sentence
|
|
RESULT_SHORT="${STATUS_ICON} Completed with ${FailNum} / ${TestsNum} failures in ${TIME_ELAPSED}"
|
|
fi
|
|
|
|
echo "RESULT_SHORT=${RESULT_SHORT}" >> $GITHUB_ENV
|
|
echo "TIME_ELAPSED=${TIME_ELAPSED}" >> $GITHUB_ENV
|
|
echo 'STAT<<EOF' >> $GITHUB_ENV
|
|
echo "${STAT}" >> $GITHUB_ENV
|
|
echo 'EOF' >> $GITHUB_ENV
|
|
- name: Set PR or Branch label for report filename
|
|
id: vars
|
|
run: |
|
|
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
echo "PR_OR_MASTER=PR${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "PR_OR_MASTER=Master" >> $GITHUB_OUTPUT
|
|
fi
|
|
echo "COMMIT_SHA=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
|
|
RUN_ID_SHORT="$GITHUB_RUN_ID"
|
|
if [ ${#RUN_ID_SHORT} -gt 7 ]; then
|
|
RUN_ID_SHORT="${RUN_ID_SHORT: -7}"
|
|
fi
|
|
echo "RUN_ID_SHORT=${RUN_ID_SHORT}" >> $GITHUB_OUTPUT
|
|
- name: Upload Gopogh report
|
|
id: upload_gopogh
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
with:
|
|
name: functional-${{ matrix.name }}-${{ steps.vars.outputs.PR_OR_MASTER }}-sha-${{ steps.vars.outputs.COMMIT_SHA }}-run-${{ steps.vars.outputs.RUN_ID_SHORT}}
|
|
path: ./report
|
|
- name: The End Result Summary ${{ matrix.name }}
|
|
shell: bash
|
|
run: |
|
|
summary="$GITHUB_STEP_SUMMARY"
|
|
Print_Gopogh_Artifact_Download_URL() {
|
|
ARTIFACT_NAME="functional-${{ matrix.name }}-${{ steps.vars.outputs.PR_OR_MASTER }}-sha-${{ steps.vars.outputs.COMMIT_SHA }}"
|
|
ARTIFACT_ID='${{ steps.upload_gopogh.outputs.artifact-id }}'
|
|
if [ -n "$ARTIFACT_ID" ]; then
|
|
URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/$ARTIFACT_ID"
|
|
echo "Gopogh report artifact ($ARTIFACT_NAME): $URL"
|
|
echo "📥 [Download Gopogh Report]($URL)" >> "$summary"
|
|
else
|
|
echo "Could not determine artifact ID (action version may not expose it). Find artifact named: $ARTIFACT_NAME"
|
|
echo "Report artifact name: $ARTIFACT_NAME" | tee -a "$summary"
|
|
fi
|
|
}
|
|
|
|
Print_Gopogh_Artifact_Download_URL
|
|
echo "-------------------- RESULT SUMMARY --------------------"
|
|
echo "$RESULT_SHORT" | tee -a "$summary"
|
|
echo "Time Elapsed: ${TIME_ELAPSED}" | tee -a "$summary"
|
|
|
|
numFail=$(echo "$STAT" | jq -r '.NumberOfFail // 0')
|
|
numPass=$(echo "$STAT" | jq -r '.NumberOfPass // 0')
|
|
numSkip=$(echo "$STAT" | jq -r '.NumberOfSkip // 0')
|
|
|
|
# Print test counts only if they are non-zero
|
|
print_test_counts_only() {
|
|
if [ -n "${numFail}" ]; then
|
|
echo "Failed: ${numFail}" | tee -a "$summary"
|
|
fi
|
|
if [ -n "${numPass}" ]; then
|
|
echo "Passed: ${numPass}" | tee -a "$summary"
|
|
fi
|
|
if [ -n "${numSkip}" ]; then
|
|
echo "Skipped: ${numSkip}" | tee -a "$summary"
|
|
fi
|
|
}
|
|
|
|
print_test_counts_only
|
|
|
|
# Prints lits of test names grouped by result status
|
|
print_test_names_by_status() {
|
|
local count="$1" header="$2" sym="$3" field="$4" to_summary="$5"
|
|
(( count > 0 )) || return 0
|
|
local line="------------------------ ${count} ${header} ------------------------"
|
|
if [ "$to_summary" = "yes" ]; then
|
|
echo "$line" | tee -a "$summary"
|
|
jq -r ".${field}[]? | \" ${sym} \(.)\"" <<<"$STAT" | tee -a "$summary"
|
|
else
|
|
echo "$line"
|
|
jq -r ".${field}[]? | \" ${sym} \(.)\"" <<<"$STAT"
|
|
fi
|
|
}
|
|
|
|
print_test_names_by_status "${numFail:-0}" "Failed" "✗" "FailedTests" yes
|
|
print_test_names_by_status "${numPass:-0}" "Passed" "✓" "PassedTests" no
|
|
print_test_names_by_status "${numSkip:-0}" "Skipped" "•" "SkippedTests" yes
|
|
echo $summary >> $GITHUB_STEP_SUMMARY
|
|
decide_exit_code() {
|
|
# Allow overriding minimum expected passes for when some tests pass and others are timed out
|
|
local min_pass="${MIN_PASS_THRESHOLD:-45}"
|
|
local timeout_pattern="Test Timed out"
|
|
|
|
echo "---------------------------------------------------------"
|
|
|
|
# Timeout detection
|
|
if echo "$RESULT_SHORT" | grep -iq "$timeout_pattern"; then
|
|
echo "*** Detected test timeout ${TIME_ELAPSED} ⌛: '$timeout_pattern' ***"
|
|
exit 3
|
|
fi
|
|
|
|
# Any failures
|
|
if [ "${numFail:-0}" -gt 0 ]; then
|
|
echo "*** ${numFail} test(s) failed ***"
|
|
exit 2
|
|
fi
|
|
|
|
# Zero passes (likely setup issue)
|
|
if [ "${numPass:-0}" -eq 0 ]; then
|
|
echo "*** No tests passed ***"
|
|
exit 4
|
|
fi
|
|
|
|
# Insufficient passes safeguard
|
|
if [ "${numPass:-0}" -lt "$min_pass" ]; then
|
|
echo "*** Only ${numPass} passed (< required ${min_pass}) ***" | tee -a "$summary"
|
|
exit 5
|
|
fi
|
|
|
|
echo "Exit criteria satisfied: ${numPass} passed, ${numFail} failed, ${numSkip} skipped."
|
|
}
|
|
|
|
decide_exit_code
|