Skip to content

Commit bda469a

Browse files
committed
Fix: Add validations to suspend_trigger (Bugfix)
* Run "systemctl list-jobs suspend" to check if there are suspend jobs running before running one more. * If "systemctl list-jobs suspend" detects suspend jobs running wait for a while before proceeding. * Set "set -o pipefail" on the Checkbox job definition for the job to be marked as "failed" when exiting on error.
1 parent aed87f5 commit bda469a

3 files changed

Lines changed: 57 additions & 1 deletion

File tree

providers/base/bin/suspend_trigger.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ def main(args=sys.argv[1:]):
6767
str(args.sleep_delay),
6868
]
6969
suspend_cmd = ["systemctl", "suspend"]
70+
list_jobs_cmd = ["systemctl", "list-jobs", "*suspend*"]
71+
timeout = 10
72+
while timeout > 0:
73+
output = subprocess.check_output(
74+
list_jobs_cmd,
75+
stderr=subprocess.STDOUT,
76+
universal_newlines=True,
77+
).strip()
78+
print(output)
79+
if "No jobs running." in output or "No jobs listed." in output:
80+
break
81+
print("Suspend jobs ongoing, waiting...")
82+
time.sleep(1)
83+
timeout -= 1
84+
else:
85+
print("Timed out waiting for suspend jobs to finish")
86+
return 1
7087
print("Running: {}".format(" ".join(rtcwake_cmd)))
7188
subprocess.check_call(rtcwake_cmd)
7289
print(
@@ -80,6 +97,8 @@ def main(args=sys.argv[1:]):
8097
print("Removing {}...".format(log_path))
8198
os.remove(log_path)
8299

100+
return 0
101+
83102

84103
if __name__ == "__main__":
85104
sys.exit(main())

providers/base/tests/test_suspend_trigger.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def test_fwts_path_on_i386_with_defaults(
7474

7575

7676
@patch("suspend_trigger.fwts_test")
77+
@patch("suspend_trigger.subprocess.check_output")
7778
@patch("suspend_trigger.subprocess.check_call")
7879
@patch("suspend_trigger.platform.machine")
7980
@patch("os.remove")
@@ -85,12 +86,14 @@ def test_rtcwake_path_success_with_args(
8586
mock_remove,
8687
mock_machine,
8788
mock_check_call,
89+
mock_check_output,
8890
mock_fwts_test,
8991
):
9092
"""
9193
Tests the rtcwake/systemctl path on aarch64 with custom arguments.
9294
"""
9395
mock_machine.return_value = "aarch64"
96+
mock_check_output.return_value = "No jobs listed."
9497

9598
suspend_trigger.main(
9699
["--sleep-delay", "25", "--rtc-device", "/dev/my_rtc"]
@@ -108,25 +111,34 @@ def test_rtcwake_path_success_with_args(
108111
"25",
109112
]
110113
expected_suspend_cmd = ["systemctl", "suspend"]
114+
expected_list_cmd = ["systemctl", "list-jobs", "*suspend*"]
115+
mock_check_output.assert_called_with(
116+
expected_list_cmd,
117+
stderr=subprocess.STDOUT,
118+
universal_newlines=True,
119+
)
111120
subprocess_calls = [
112121
call(expected_rtcwake_cmd),
113122
call(expected_suspend_cmd),
114123
]
115124
mock_check_call.assert_has_calls(subprocess_calls)
116125
self.assertEqual(mock_check_call.call_count, 2)
126+
self.assertEqual(mock_check_output.call_count, 1)
117127

118128
def test_rtcwake_path_with_defaults(
119129
self,
120130
mock_exists,
121131
mock_remove,
122132
mock_machine,
123133
mock_check_call,
134+
mock_check_output,
124135
mock_fwts_test,
125136
):
126137
"""
127138
Tests the rtcwake/systemctl path without any argument.
128139
"""
129140
mock_machine.return_value = "riscv64"
141+
mock_check_output.return_value = "No jobs listed."
130142

131143
suspend_trigger.main([])
132144

@@ -141,6 +153,12 @@ def test_rtcwake_path_with_defaults(
141153
"30",
142154
]
143155
expected_suspend_cmd = ["systemctl", "suspend"]
156+
expected_list_cmd = ["systemctl", "list-jobs", "*suspend*"]
157+
mock_check_output.assert_called_with(
158+
expected_list_cmd,
159+
stderr=subprocess.STDOUT,
160+
universal_newlines=True,
161+
)
144162
subprocess_calls = [
145163
call(expected_rtcwake_cmd),
146164
call(expected_suspend_cmd),
@@ -153,12 +171,14 @@ def test_rtcwake_command_failure(
153171
mock_remove,
154172
mock_machine,
155173
mock_check_call,
174+
mock_check_output,
156175
mock_fwts_test,
157176
):
158177
"""
159178
Tests the case where the rtcwake command fails.
160179
"""
161180
mock_machine.return_value = "aarch64"
181+
mock_check_output.return_value = "No jobs listed."
162182
# Simulate a command failure
163183
error = subprocess.CalledProcessError(
164184
returncode=1, cmd="rtcwake", output="Error from rtcwake"
@@ -169,7 +189,8 @@ def test_rtcwake_command_failure(
169189
with self.assertRaises(subprocess.CalledProcessError):
170190
suspend_trigger.main([])
171191

172-
# Verify that only the first command (rtcwake) was attempted
192+
# Verify that only the first 2 commands were attempted
193+
self.assertTrue(mock_check_output.called)
173194
self.assertTrue(mock_check_call.called)
174195
self.assertIn("rtcwake", mock_check_call.call_args[0][0])
175196

@@ -179,12 +200,14 @@ def test_suspend_command_failure(
179200
mock_remove,
180201
mock_machine,
181202
mock_check_call,
203+
mock_check_output,
182204
mock_fwts_test,
183205
):
184206
"""
185207
Tests the case where the systemctl suspend command fails.
186208
"""
187209
mock_machine.return_value = "aarch64"
210+
mock_check_output.return_value = "No jobs listed."
188211
suspend_error = subprocess.CalledProcessError(
189212
returncode=1, cmd="systemctl suspend", output="Error from suspend"
190213
)
@@ -195,6 +218,7 @@ def test_suspend_command_failure(
195218
suspend_trigger.main([])
196219

197220
# Verify both commands were attempted
221+
self.assertTrue(mock_check_output.called)
198222
self.assertEqual(mock_check_call.call_count, 2)
199223
self.assertIn("rtcwake", mock_check_call.call_args_list[0][0][0])
200224
self.assertIn("systemctl", mock_check_call.call_args_list[1][0][0])
@@ -205,6 +229,7 @@ def test_log_file_removed_if_exists(
205229
mock_remove,
206230
mock_machine,
207231
mock_check_call,
232+
mock_check_output,
208233
mock_fwts_test,
209234
):
210235
"""
@@ -214,10 +239,17 @@ def test_log_file_removed_if_exists(
214239
mock_machine.return_value = "aarch64"
215240
mock_exists.return_value = True # Simulate file exists
216241
mock_check_call.side_effect = [None, None]
242+
mock_check_output.return_value = "No jobs listed."
217243

218244
suspend_trigger.main([])
219245

220246
# Verify commands were called
247+
expected_list_cmd = ["systemctl", "list-jobs", "*suspend*"]
248+
mock_check_output.assert_called_with(
249+
expected_list_cmd,
250+
stderr=subprocess.STDOUT,
251+
universal_newlines=True,
252+
)
221253
expected_rtcwake_cmd = [
222254
"rtcwake",
223255
"--verbose",
@@ -246,6 +278,7 @@ def test_log_file_not_removed_if_missing(
246278
mock_remove,
247279
mock_machine,
248280
mock_check_call,
281+
mock_check_output,
249282
mock_fwts_test,
250283
):
251284
"""
@@ -254,6 +287,7 @@ def test_log_file_not_removed_if_missing(
254287
mock_machine.return_value = "aarch64"
255288
mock_exists.return_value = False # Simulate file missing
256289
mock_check_call.side_effect = [None, None]
290+
mock_check_output.return_value = "No jobs listed."
257291

258292
suspend_trigger.main([])
259293
# Verify remove was never called

providers/base/units/stress/suspend_cycles_reboot.pxu

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ estimated_duration: 75.0
7979
environ: PLAINBOX_SESSION_SHARE STRESS_S3_INIT_DELAY STRESS_S3_SLEEP_DELAY STRESS_S3_WAIT_DELAY LD_LIBRARY_PATH RTC_DEVICE_FILE
8080
user: root
8181
command:
82+
set -o pipefail
8283
echo "Current boot ID is: $(tr -d - < /proc/sys/kernel/random/boot_id)"
8384
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
8485
summary:
@@ -105,6 +106,7 @@ environ: PLAINBOX_SESSION_SHARE STRESS_S3_INIT_DELAY STRESS_S3_SLEEP_DELAY STRES
105106
after: stress-tests/suspend_cycles_reboot{{suspend_reboot_previous}}
106107
user: root
107108
command:
109+
set -o pipefail
108110
echo "Current boot ID is: $(tr -d - < /proc/sys/kernel/random/boot_id)"
109111
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
110112
summary:
@@ -129,6 +131,7 @@ environ: PLAINBOX_SESSION_SHARE STRESS_S3_INIT_DELAY STRESS_S3_SLEEP_DELAY STRES
129131
after: stress-tests/suspend_cycles_{{suspend_id_previous}}_reboot{{suspend_reboot_id}}
130132
user: root
131133
command:
134+
set -o pipefail
132135
echo "Current boot ID is: $(tr -d - < /proc/sys/kernel/random/boot_id)"
133136
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
134137
summary:

0 commit comments

Comments
 (0)