Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(node): setupos unit tests #3661

Merged
merged 24 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cce32b2
normalize config.sh
andrewbattat Jan 21, 2025
9bc7442
Merge branch 'master' into andrew/setupos-unit-tests
andrewbattat Jan 28, 2025
a0fef8f
Add test-setupos.sh unit tests
andrewbattat Jan 28, 2025
997e3a8
Remove unnecessary comment
andrewbattat Jan 28, 2025
e298eb6
Fix pre-commit
andrewbattat Jan 28, 2025
3f99fa2
Fix buildifier
andrewbattat Jan 29, 2025
5d91b85
Merge branch 'master' into andrew/setupos-unit-tests
andrewbattat Feb 18, 2025
5523074
Make test_setupos non-manual
andrewbattat Feb 18, 2025
9f6c81f
Add check-hardware unit tests
andrewbattat Feb 18, 2025
b43f8fe
Refactor test-setupos.sh
andrewbattat Feb 18, 2025
f39cc75
Remove log_ mocked functions
andrewbattat Feb 18, 2025
fff9e91
Refactor log_and_halt_installation_on_error
andrewbattat Feb 18, 2025
e17dff3
Add test_verify_cpu_gen1_failure
andrewbattat Feb 18, 2025
9ff9ad1
Add missing unit tests
andrewbattat Feb 18, 2025
89901d1
Remove unnecessary || return statements
andrewbattat Feb 18, 2025
0c5ce69
Fix buldifier and pre-commit
andrewbattat Feb 18, 2025
ee87cd0
Fix test_validate_domain_name logs
andrewbattat Feb 19, 2025
e824195
Refactor test_validate_domain_name to separate test cases and the act…
andrewbattat Feb 19, 2025
a02af99
Separate test cases and test logic for test_detect_hardware_generation
andrewbattat Feb 19, 2025
df5e11b
Separate test cases and test logic fortest_verify_cpu
andrewbattat Feb 19, 2025
c5d0e65
Separate test cases and test logic for test_verify_memory
andrewbattat Feb 19, 2025
f4305df
Catch failure errors more explicitly
andrewbattat Feb 19, 2025
ce36455
Remove unnecessary comment
andrewbattat Feb 19, 2025
25e1511
Fix pre-commit
andrewbattat Feb 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions ic-os/components/setupos-scripts/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,16 @@ sh_test(
srcs = ["test-kernel-cmdline-function-runner"],
data = [":functions.sh"],
)

sh_test(
name = "test_setupos",
srcs = ["test-setupos.sh"],
args = [
"$(execpath check-network.sh)",
"$(execpath check-hardware.sh)",
],
data = [
"check-hardware.sh",
"check-network.sh",
],
)
238 changes: 238 additions & 0 deletions ic-os/components/setupos-scripts/test-setupos.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#!/usr/bin/env bash

set -euo pipefail

CHECK_NETWORK_SCRIPT="${1:-./check-network.sh}"
CHECK_HARDWARE_SCRIPT="${2:-./check-hardware.sh}"

# ------------------------------------------------------------------------------
# Override "source" for test environment.
# ------------------------------------------------------------------------------
function source() {
if [[ "$1" == "/opt/ic/bin/config.sh" || "$1" == "/opt/ic/bin/functions.sh" ]]; then
echo "MOCKED: ignoring source of '$1' (file not present in test environment)"
return
fi
builtin source "$1"
}

# ------------------------------------------------------------------------------
# Mocked Functions
# ------------------------------------------------------------------------------

function log_and_halt_installation_on_error() {
if [ "$1" != "0" ]; then
echo "ERROR encountered: $2"
exit 1
fi
}

# ------------------------------------------------------------------------------
# Unit tests for check-network.sh
# ------------------------------------------------------------------------------

function test_validate_domain_name() {
r-birkner marked this conversation as resolved.
Show resolved Hide resolved
declare -A test_cases=(
["example.com"]=0
["node1.example.com"]=0
["example-.com"]=1
["example."]=1
["&BadDOMAIN.com"]=1
)

for domain in "${!test_cases[@]}"; do
expected="${test_cases[$domain]}"
echo "Running test for domain: $domain"
domain_name="$domain"

if (validate_domain_name); then
if [[ "$expected" -eq 0 ]]; then
echo " PASS: valid domain: $domain"
else
echo " FAIL: domain ($domain) validation was expected to fail but didn't"
exit 1
fi
else
if [[ "$expected" -eq 1 ]]; then
echo " PASS: domain ($domain) validation failed as expected"
else
echo " FAIL: invalid domain ($domain) was incorrectly marked as valid"
exit 1
fi
fi
done
}

# ------------------------------------------------------------------------------
# Parameterized unit test for check-hardware.sh
# ------------------------------------------------------------------------------

function test_detect_hardware_generation() {
# Gen1 test
test_detect_hardware_generation_helper "1" '[
{"id": "cpu:0", "product": "AMD EPYC 7302", "capabilities": {"sev": "true"}},
{"id": "cpu:1", "product": "AMD EPYC 7302", "capabilities": {"sev": "true"}}
]'
# Gen2 test
test_detect_hardware_generation_helper "2" '[
{"id": "cpu:0", "product": "AMD EPYC 7313", "capabilities": {"sev_snp": "true"}},
{"id": "cpu:1", "product": "AMD EPYC 7313", "capabilities": {"sev_snp": "true"}}
]'
}

function test_detect_hardware_generation_helper() {
local expected_hardware_generation="$1"
local FAKE_CPU_JSON="$2"
echo "Running test: test_detect_hardware_generation for Gen${expected_hardware_generation}"

function get_cpu_info_json() { echo "$FAKE_CPU_JSON"; }
HARDWARE_GENERATION=""

detect_hardware_generation
if [[ "$HARDWARE_GENERATION" == "${expected_hardware_generation}" ]]; then
echo " PASS: Gen${expected_hardware_generation} hardware detected"
else
echo " FAIL: Gen${expected_hardware_generation} hardware not detected as expected"
exit 1
fi
}

function test_verify_cpu() {
# Gen1 Success
test_verify_cpu_helper "verify_cpu Gen1 success" "1" '[
{"id": "cpu:0", "product": "AMD EPYC 7302", "capabilities": {"sev": "true"}},
{"id": "cpu:1", "product": "AMD EPYC 7302", "capabilities": {"sev": "true"}}
]' 64 0

# Gen1 Failure
test_verify_cpu_helper "verify_cpu Gen1 failure" "1" '[
{"id": "cpu:0", "product": "Invalid CPU", "capabilities": {"sev": "false"}},
{"id": "cpu:1", "product": "Invalid CPU", "capabilities": {"sev": "false"}}
]' 64 1

# Gen2 Success
test_verify_cpu_helper "verify_cpu Gen2 success" "2" '[
{"id": "cpu:0", "product": "AMD EPYC 7313", "capabilities": {"sev_snp": "true"}},
{"id": "cpu:1", "product": "AMD EPYC 7313", "capabilities": {"sev_snp": "true"}}
]' 70 0

# Gen2 Failure
test_verify_cpu_helper "verify_cpu Gen2 failure" "2" '[
{"id": "cpu:0", "product": "AMD EPYC 7313", "capabilities": {"sev_snp": "false"}},
{"id": "cpu:1", "product": "AMD EPYC 7313", "capabilities": {"sev_snp": "false"}}
]' 64 1
}

function test_verify_cpu_helper() {
local test_label="$1"
local HARDWARE_GENERATION="$2"
local FAKE_CPU_JSON="$3"
local nproc_val="$4"
local expected_result="$5"

echo "Running test: ${test_label}"
function get_cpu_info_json() { echo "$FAKE_CPU_JSON"; }
function nproc() { echo "$nproc_val"; }

if [ "$expected_result" -eq 0 ]; then
if (verify_cpu); then
echo " PASS: ${test_label} passed"
else
echo " FAIL: ${test_label} expected to pass but failed"
exit 1
fi
else
if ! (verify_cpu); then
echo " PASS: ${test_label} failed as expected"
else
echo " FAIL: ${test_label} passed unexpectedly"
exit 1
fi
fi
}

function test_verify_memory() {
# Sufficient memory case:
test_verify_memory_helper 600000000000 0
# Insufficient memory case:
test_verify_memory_helper 100000000000 1
}

function test_verify_memory_helper() {
local memory_size="$1"
local expected_result="$2"
echo "Running test: test_verify_memory with memory size: $memory_size"
function lshw() {
if [[ "$*" == *"-class memory"* ]]; then
echo "[{\"id\": \"memory\", \"size\": $memory_size}]"
return 0
fi
return 1
}

if [ "$expected_result" -eq 0 ]; then
if (verify_memory); then
echo " PASS: verify_memory passed with sufficient memory"
else
echo " FAIL: verify_memory expected to pass with sufficient memory but failed"
exit 1
fi
else
if ! (verify_memory); then
echo " PASS: verify_memory failed as expected with insufficient memory"
else
echo " FAIL: verify_memory passed unexpectedly with insufficient memory"
exit 1
fi
fi
}

function test_verify_deployment_path_warning() {
echo "Running test: test_verify_deployment_path_warning"
HARDWARE_GENERATION="2"
function sleep() {
echo "Sleep skipped for test"
}
output=$(verify_deployment_path 2>&1)
if [[ "$output" == *"WARNING: Gen2 hardware detected"* ]]; then
echo " PASS: verify_deployment_path warned as expected"
else
echo " FAIL: verify_deployment_path did not warn as expected"
exit 1
fi
}

# ------------------------------------------------------------------------------
# Load scripts WITHOUT executing main() function.
# ------------------------------------------------------------------------------
for script in "${CHECK_NETWORK_SCRIPT}" "${CHECK_HARDWARE_SCRIPT}"; do
if [[ -f "${script}" ]]; then
tmpfile=$(mktemp)
sed '/^main$/d' "${script}" >"${tmpfile}"
source "${tmpfile}"
rm "${tmpfile}"
fi
done

# ------------------------------------------------------------------------------
# Run all tests
# ------------------------------------------------------------------------------
echo
echo "Running check-network.sh unit tests..."
test_validate_domain_name
echo
echo "PASSED check-network unit tests"
echo

echo
echo "Running check-hardware.sh unit tests..."
test_detect_hardware_generation
test_verify_cpu
test_verify_memory
test_verify_deployment_path_warning
echo
echo "PASSED check-hardware unit tests"
echo

echo
echo "All tests passed."