Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 7 additions & 2 deletions checkbox-support/checkbox_support/scripts/fwts_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@
print("WARNING: Found bad char in " + logfile)


def main():
def parse_arguments(args):
description_text = "Tests the system BIOS using the Firmware Test Suite"
epilog_text = (
"To perform sleep testing, you will need at least some of "
Expand Down Expand Up @@ -388,7 +388,12 @@
action="store_true",
help=("List all Server Certification concerned tests " "in fwts"),
)
args = parser.parse_args()
args = parser.parse_args(args)
return args

Check warning on line 392 in checkbox-support/checkbox_support/scripts/fwts_test.py

View check run for this annotation

Codecov / codecov/patch

checkbox-support/checkbox_support/scripts/fwts_test.py#L391-L392

Added lines #L391 - L392 were not covered by tests


def main(args=sys.argv[1:]):
args = parse_arguments(args)

Check warning on line 396 in checkbox-support/checkbox_support/scripts/fwts_test.py

View check run for this annotation

Codecov / codecov/patch

checkbox-support/checkbox_support/scripts/fwts_test.py#L396

Added line #L396 was not covered by tests

tests = []
requested_tests = []
Expand Down
15 changes: 0 additions & 15 deletions providers/base/bin/suspend.sh

This file was deleted.

78 changes: 78 additions & 0 deletions providers/base/bin/suspend_trigger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3

import argparse
import platform
import subprocess
import sys
import time

from checkbox_support.scripts import fwts_test


def main(args=sys.argv[1:]):
parser = argparse.ArgumentParser()
parser.add_argument(
"--wait",
type=int,
help="Time (in seconds) to wait before triggering suspend.",
)
parser.add_argument(
"--check-delay",
type=int,
help=(
"Time (in seconds) for FWTS to wait before checking the device "
"after resuming."
),
default=45,
)
parser.add_argument(
"--sleep-delay",
type=int,
help="Time (in seconds) to sleep before resuming the device.",
default=30,
)
parser.add_argument(
"--rtc-device",
help="Real Time Clock device to use (for ARM devices only)",
default="/dev/rtc0",
)
args = parser.parse_args(args)
if args.wait:
print("Waiting for {} seconds...".format(args.wait))
time.sleep(args.wait)
if platform.machine() in ["i386", "x86_64"]:
print("Running FWTS to trigger suspend...")
fwts_args = [
"-f",
"none",
"-s",
"s3",
"--s3-device-check",
"--s3-device-check-delay",
str(args.check_delay),
"--s3-sleep-delay",
str(args.sleep_delay),
]
fwts_test.main(fwts_args)
else:
rtcwake_cmd = [
"rtcwake",
"--verbose",
"--device",
args.rtc_device,
"--mode",
"no",
"--seconds",
str(args.sleep_delay),
]
suspend_cmd = ["systemctl", "suspend"]
print("Running: {}".format(" ".join(rtcwake_cmd)))
subprocess.check_call(rtcwake_cmd)
print(
"Running: {} to suspend the system".format(" ".join(suspend_cmd))
)
subprocess.check_call(suspend_cmd)


if __name__ == "__main__":
sys.exit(main())
178 changes: 178 additions & 0 deletions providers/base/tests/test_suspend_trigger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#!/usr/bin/env python3

import unittest
from unittest.mock import patch, call
import subprocess

import suspend_trigger


@patch("suspend_trigger.fwts_test")
@patch("suspend_trigger.time.sleep")
@patch("suspend_trigger.platform.machine")
class TestSuspendTriggerFWTS(unittest.TestCase):

def test_wait_argument(self, mock_machine, mock_sleep, mock_fwts_test):
"""
Tests if the --wait argument correctly calls time.sleep.
"""
mock_machine.return_value = "x86_64"
suspend_trigger.main(["--wait", "15"])
mock_sleep.assert_called_once_with(15)
# Verify that the rest of the script (fwts path) also runs
self.assertTrue(mock_fwts_test.main.called)

def test_fwts_path_on_x86_64_with_arguments(
self, mock_machine, mock_sleep, mock_fwts_test
):
"""
Tests the FWTS code path on x86_64 architecture with custom arguments.
"""
mock_machine.return_value = "x86_64"

suspend_trigger.main(["--sleep-delay", "22", "--check-delay", "55"])

mock_sleep.assert_not_called()
self.assertTrue(mock_machine.called)
expected_fwts_args = [
"-f",
"none",
"-s",
"s3",
"--s3-device-check",
"--s3-device-check-delay",
"55",
"--s3-sleep-delay",
"22",
]
mock_fwts_test.main.assert_called_once_with(expected_fwts_args)

def test_fwts_path_on_i386_with_defaults(
self, mock_machine, mock_sleep, mock_fwts_test
):
"""
Tests the FWTS code path on i386 with no arguments.
"""
# Mock os.getenv to return the default value passed to it in the script
mock_machine.return_value = "i386"

suspend_trigger.main([])

mock_sleep.assert_not_called()
expected_fwts_args = [
"-f",
"none",
"-s",
"s3",
"--s3-device-check",
"--s3-device-check-delay",
"45", # Default from script
"--s3-sleep-delay",
"30", # Default from script
]
mock_fwts_test.main.assert_called_once_with(expected_fwts_args)


@patch("suspend_trigger.fwts_test")
@patch("suspend_trigger.subprocess.check_call")
@patch("suspend_trigger.platform.machine")
class TestSuspendTriggerRTCWake(unittest.TestCase):
def test_rtcwake_path_success_with_args(
self, mock_machine, mock_check_call, mock_fwts_test
):
"""
Tests the rtcwake/systemctl path on aarch64 with custom arguments.
"""
mock_machine.return_value = "aarch64"

suspend_trigger.main(
["--sleep-delay", "25", "--rtc-device", "/dev/my_rtc"]
)

self.assertFalse(mock_fwts_test.main.called)
expected_rtcwake_cmd = [
"rtcwake",
"--verbose",
"--device",
"/dev/my_rtc",
"--mode",
"no",
"--seconds",
"25",
]
expected_suspend_cmd = ["systemctl", "suspend"]
subprocess_calls = [
call(expected_rtcwake_cmd),
call(expected_suspend_cmd),
]
mock_check_call.assert_has_calls(subprocess_calls)
self.assertEqual(mock_check_call.call_count, 2)

def test_rtcwake_path_with_defaults(
self, mock_machine, mock_check_call, mock_fwts_test
):
"""
Tests the rtcwake/systemctl path without any argument.
"""
mock_machine.return_value = "riscv64"

suspend_trigger.main([])

expected_rtcwake_cmd = [
"rtcwake",
"--verbose",
"--device",
"/dev/rtc0",
"--mode",
"no",
"--seconds",
"30",
]
expected_suspend_cmd = ["systemctl", "suspend"]
subprocess_calls = [
call(expected_rtcwake_cmd),
call(expected_suspend_cmd),
]
mock_check_call.assert_has_calls(subprocess_calls)

def test_rtcwake_command_failure(
self, mock_machine, mock_check_call, mock_fwts_test
):
"""
Tests the case where the rtcwake command fails.
"""
mock_machine.return_value = "aarch64"
# Simulate a command failure
error = subprocess.CalledProcessError(
returncode=1, cmd="rtcwake", output="Error from rtcwake"
)
mock_check_call.side_effect = error

# The script should propagate the exception
with self.assertRaises(subprocess.CalledProcessError):
suspend_trigger.main([])

# Verify that only the first command (rtcwake) was attempted
self.assertTrue(mock_check_call.called)
self.assertIn("rtcwake", mock_check_call.call_args[0][0])

def test_suspend_command_failure(
self, mock_machine, mock_check_call, mock_fwts_test
):
"""
Tests the case where the systemctl suspend command fails.
"""
mock_machine.return_value = "aarch64"
suspend_error = subprocess.CalledProcessError(
returncode=1, cmd="systemctl suspend", output="Error from suspend"
)
# The first call (rtcwake) succeeds, the second (suspend) fails.
mock_check_call.side_effect = [None, suspend_error]

with self.assertRaises(subprocess.CalledProcessError):
suspend_trigger.main([])

# Verify both commands were attempted
self.assertEqual(mock_check_call.call_count, 2)
self.assertIn("rtcwake", mock_check_call.call_args_list[0][0][0])
self.assertIn("systemctl", mock_check_call.call_args_list[1][0][0])
12 changes: 6 additions & 6 deletions providers/base/units/stress/suspend_cycles_reboot.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ requires:
sleep.mem == 'supported'
rtc.state == 'supported'
estimated_duration: 75.0
environ: PLAINBOX_SESSION_SHARE STRESS_S3_SLEEP_DELAY STRESS_S3_WAIT_DELAY LD_LIBRARY_PATH RTC_DEVICE_FILE
environ: PLAINBOX_SESSION_SHARE STRESS_S3_INIT_DELAY STRESS_S3_SLEEP_DELAY STRESS_S3_WAIT_DELAY LD_LIBRARY_PATH RTC_DEVICE_FILE
user: root
command:
echo "Current boot ID is: $(tr -d - < /proc/sys/kernel/random/boot_id)"
suspend.sh 2>&1 | tee -a "$PLAINBOX_SESSION_SHARE"/suspend_cycles_with_reboot_total.log
suspend_trigger.py --wait "${STRESS_S3_INIT_DELAY:-120}" --check-delay "${STRESS_S3_WAIT_DELAY:-45}" --sleep-delay "${STRESS_S3_SLEEP_DELAY:-30}" --rtc-device "${RTC_DEVICE_FILE:-/dev/rtc0}" 2>&1 | tee -a "$PLAINBOX_SESSION_SHARE"/suspend_cycles_with_reboot_total.log
summary:
Suspend and resume device (suspend cycle 1, reboot cycle 1)
_purpose: Suspend and resume device (suspend cycle 1, reboot cycle 1)
Expand All @@ -101,12 +101,12 @@ requires:
sleep.mem == 'supported'
rtc.state == 'supported'
estimated_duration: 75.0
environ: PLAINBOX_SESSION_SHARE STRESS_S3_SLEEP_DELAY STRESS_S3_WAIT_DELAY LD_LIBRARY_PATH RTC_DEVICE_FILE
environ: PLAINBOX_SESSION_SHARE STRESS_S3_INIT_DELAY STRESS_S3_SLEEP_DELAY STRESS_S3_WAIT_DELAY LD_LIBRARY_PATH RTC_DEVICE_FILE
after: stress-tests/suspend_cycles_reboot{{suspend_reboot_previous}}
user: root
command:
echo "Current boot ID is: $(tr -d - < /proc/sys/kernel/random/boot_id)"
suspend.sh 2>&1 | tee -a "$PLAINBOX_SESSION_SHARE"/suspend_cycles_with_reboot_total.log
suspend_trigger.py --wait "${STRESS_S3_INIT_DELAY:-120}" --check-delay "${STRESS_S3_WAIT_DELAY:-45}" --sleep-delay "${STRESS_S3_SLEEP_DELAY:-30}" --rtc-device "${RTC_DEVICE_FILE:-/dev/rtc0}" 2>&1 | tee -a "$PLAINBOX_SESSION_SHARE"/suspend_cycles_with_reboot_total.log
summary:
Suspend and resume device (suspend cycle 1, reboot cycle {{suspend_reboot_id}})

Expand All @@ -125,12 +125,12 @@ requires:
sleep.mem == 'supported'
rtc.state == 'supported'
estimated_duration: 75.0
environ: PLAINBOX_SESSION_SHARE STRESS_S3_SLEEP_DELAY STRESS_S3_WAIT_DELAY LD_LIBRARY_PATH
environ: PLAINBOX_SESSION_SHARE STRESS_S3_INIT_DELAY STRESS_S3_SLEEP_DELAY STRESS_S3_WAIT_DELAY LD_LIBRARY_PATH RTC_DEVICE_FILE
after: stress-tests/suspend_cycles_{{suspend_id_previous}}_reboot{{suspend_reboot_id}}
user: root
command:
echo "Current boot ID is: $(tr -d - < /proc/sys/kernel/random/boot_id)"
suspend.sh 2>&1 | tee -a "$PLAINBOX_SESSION_SHARE"/suspend_cycles_with_reboot_total.log
suspend_trigger.py --check-delay "${STRESS_S3_WAIT_DELAY:-45}" --sleep-delay "${STRESS_S3_SLEEP_DELAY:-30}" --rtc-device "${RTC_DEVICE_FILE:-/dev/rtc0}" 2>&1 | tee -a "$PLAINBOX_SESSION_SHARE"/suspend_cycles_with_reboot_total.log
summary:
Suspend and resume device (suspend cycle {{suspend_id}}, reboot cycle {{suspend_reboot_id}})
_summary:
Expand Down
Loading