Skip to content

Commit a63674d

Browse files
Use retry decorator per Pierre's suggestion
1 parent 924ecda commit a63674d

File tree

3 files changed

+105
-41
lines changed

3 files changed

+105
-41
lines changed

providers/base/bin/wol_client.py

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,47 +28,83 @@
2828
import socket
2929
import fcntl
3030
import struct
31+
from checkbox_support.helpers.retry import retry
3132

3233

33-
def send_request_to_wol_server(url, data=None, retry=3):
34+
@retry(max_attempts=3, delay=2)
35+
def send_request_to_wol_server(url, data=None):
3436
# Convert data to JSON format
3537
data_encoded = json.dumps(data).encode("utf-8")
3638

3739
# Construct request
3840
headers = {"Content-Type": "application/json"}
3941
req = urllib.request.Request(url, data=data_encoded, headers=headers)
4042

41-
attempts = 0
42-
while attempts < retry:
43-
try:
44-
with urllib.request.urlopen(req) as response:
45-
logging.info("in the urllib request.")
46-
response_data = json.loads(response.read().decode("utf-8"))
47-
logging.debug(
48-
"Response message: {}".format(response_data["message"])
43+
logging.info("Sending request to Wake-on-LAN server.")
44+
45+
try:
46+
with urllib.request.urlopen(req) as response:
47+
logging.info("In the urllib request.")
48+
response_data = json.loads(response.read().decode("utf-8"))
49+
logging.debug(
50+
"Response message: {}".format(response_data["message"])
51+
)
52+
status_code = response.status
53+
logging.debug("Status code: {}".format(status_code))
54+
55+
if status_code == 200:
56+
logging.info(
57+
"Request to Wake-on-LAN server sent successfully."
4958
)
50-
status_code = response.status
51-
logging.debug("Status code: {}".format(status_code))
52-
if status_code == 200:
53-
logging.info(
54-
"Request to Wake-on-LAN server sent successfully."
59+
return
60+
else:
61+
# If the status code is not 200, we regard the attempt as
62+
# failed and throw an exception so that the decorator can
63+
# catch it and retry.
64+
raise RuntimeError(
65+
"WOL server returned non-200 status: {}".format(
66+
status_code
5567
)
56-
return
57-
else:
58-
logging.error(
59-
"Failed to send request to Wake-on-LAN server."
60-
)
61-
except Exception as e:
62-
logging.error("An unexpected error occurred: {}".format(e))
68+
)
6369

64-
attempts += 1
65-
time.sleep(1) # Wait for a second before retrying
66-
logging.debug("Retrying... ({}/{})".format(attempts, retry))
70+
except urllib.error.URLError as e:
71+
# Handle connection errors like "Connection refused"
72+
error_msg = "Failed to connect to WOL server {}: {}".format(
73+
url, e.reason
74+
)
6775

68-
raise SystemExit(
69-
"Failed to send request to WOL server. "
70-
"Please ensure the WOL server setup correctlly."
71-
)
76+
# Provide more specific error messages for common connection issues
77+
if hasattr(e.reason, "errno"):
78+
if e.reason.errno == 111: # Connection refused
79+
error_msg = (
80+
"Connection refused - WOL server may not be "
81+
"running at {}".format(url)
82+
)
83+
elif e.reason.errno == 110: # Connection timed out
84+
error_msg = (
85+
"Connection timed out - server took too long to "
86+
"respond at {}".format(url)
87+
)
88+
89+
logging.error(error_msg)
90+
# Re-raise as RuntimeError to trigger retry mechanism
91+
raise RuntimeError(error_msg) from e
92+
93+
except json.JSONDecodeError as e:
94+
# Handle JSON parsing errors
95+
error_msg = "Failed to parse server response as JSON: {}".format(e)
96+
logging.error(error_msg)
97+
raise RuntimeError(error_msg) from e
98+
99+
except Exception as e:
100+
# Catch any other unexpected exceptions
101+
error_msg = (
102+
"Unexpected error while sending request to WOL server: {}".format(
103+
e
104+
)
105+
)
106+
logging.error(error_msg)
107+
raise RuntimeError(error_msg) from e
72108

73109

74110
def check_wakeup(interface):
@@ -241,7 +277,7 @@ def main():
241277
)
242278

243279
delay = args.delay
244-
retry = args.retry
280+
num_retry = args.retry
245281

246282
ip = get_ip_address(args.interface)
247283
mac = get_mac_address(args.interface)
@@ -260,9 +296,9 @@ def main():
260296
"wake_type": args.waketype,
261297
}
262298

263-
send_request_to_wol_server(url, data=req, retry=retry)
299+
send_request_to_wol_server(url, data=req)
264300

265-
bring_up_system("rtc", delay * retry * 2)
301+
bring_up_system("rtc", delay * num_retry * 2)
266302

267303
# write the time stamp
268304
write_timestamp(args.timestamp_file)

providers/base/tests/test_wol_client.py

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@
3636
main,
3737
)
3838

39+
from checkbox_support.helpers.retry import mock_retry
3940

41+
42+
@mock_retry()
4043
class TestSendRequestToWolServerFunction(unittest.TestCase):
4144
@patch("urllib.request.urlopen")
4245
def test_send_request_success(self, mock_urlopen):
@@ -61,41 +64,67 @@ def test_send_request_failed_status_not_200(self, mock_urlopen):
6164
mock_response.read.return_value = json.dumps(
6265
{"message": "failure"}
6366
).encode("utf-8")
64-
mock_response.getcode.return_value = 400
65-
mock_urlopen.return_value = mock_response
67+
mock_response.status = 400
6668
mock_urlopen.return_value.__enter__.return_value = mock_response
6769

68-
with self.assertRaises(SystemExit):
70+
with self.assertRaises(RuntimeError) as context:
6971
send_request_to_wol_server(
7072
"http://192.168.1.1", data={"key": "value"}
7173
)
7274

75+
self.assertIn(
76+
"WOL server returned non-200 status: 400", str(context.exception)
77+
)
78+
7379
@patch("urllib.request.urlopen")
7480
def test_send_request_failed_response_not_success(self, mock_urlopen):
7581
mock_response = MagicMock()
7682
mock_response.read.return_value = json.dumps(
7783
{"message": "failure"}
7884
).encode("utf-8")
79-
mock_response.getcode.return_value = 500
80-
mock_urlopen.return_value = mock_response
85+
86+
mock_response.status = 500
8187
mock_urlopen.return_value.__enter__.return_value = mock_response
8288

83-
with self.assertRaises(SystemExit):
89+
with self.assertRaises(RuntimeError) as context:
90+
send_request_to_wol_server(
91+
"http://192.168.1.1", data={"key": "value"}
92+
)
93+
94+
self.assertIn(
95+
"WOL server returned non-200 status: 500", str(context.exception)
96+
)
97+
98+
@patch("wol_client.urllib.request.urlopen")
99+
def test_json_decode_error(self, mock_urlopen):
100+
# Mock json decode error
101+
mock_response = MagicMock()
102+
mock_response.status = 200
103+
mock_response.read.return_value = b"Invalid JSON response"
104+
mock_response.__enter__.return_value = mock_response
105+
106+
mock_urlopen.return_value = mock_response
107+
108+
with self.assertRaises(RuntimeError) as context:
84109
send_request_to_wol_server(
85110
"http://192.168.1.1", data={"key": "value"}
86111
)
87112

113+
self.assertIn(
114+
"Failed to parse server response as JSON", str(context.exception)
115+
)
116+
88117
@patch("urllib.request.urlopen")
89118
def test_send_request_unexpected_exception(self, mock_urlopen):
90119
# Mock an unexpected exception
91120
mock_urlopen.side_effect = Exception("Unexpected error")
92121

93-
with self.assertRaises(SystemExit):
122+
with self.assertRaises(Exception) as context:
94123
send_request_to_wol_server(
95124
"http://192.168.1.1", data={"key": "value"}
96125
)
97126

98-
self.assertEqual(mock_urlopen.call_count, 3)
127+
self.assertIn("Unexpected error", str(context.exception))
99128

100129

101130
class TestCheckWakeup(unittest.TestCase):
@@ -423,7 +452,6 @@ def test_main_success(
423452
"retry_times": 3,
424453
"wake_type": "magic_packet",
425454
},
426-
retry=3,
427455
)
428456
mock_bring_up_system.assert_called_once_with("rtc", 10 * 3 * 2)
429457
mock_write_timestamp.assert_called_once_with("/tmp/timestamp")

providers/base/units/ethernet/wake-on-LAN-automatic-tests.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ DUT:
3131
- The time (in seconds) to wait between sending the Wake-on-LAN packet and checking for a response from the target device.
3232
- Example: WAKE_ON_LAN_DELAY=60
3333
- WAKE_ON_LAN_RETRY
34-
- The number of times to retry sending the Wake-on-LAN packet if the initial attempt fails.
34+
- The number of times the server retries sending the Wake-on-LAN packet if the initial attempt fails.
3535
- Example: WAKE_ON_LAN_RETRY=3
3636

3737
## Test scripts

0 commit comments

Comments
 (0)