Skip to content

Commit c13c505

Browse files
Merge branch 'reboot' into gnoi_reboot_tests
2 parents 6c553c3 + 9fcacf4 commit c13c505

File tree

2 files changed

+90
-12
lines changed

2 files changed

+90
-12
lines changed

tests/common/plugins/loganalyzer/__init__.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ def loganalyzer(duthosts, request, log_rotate_modular_chassis):
6868
yield
6969
return
7070

71+
# Skip LogAnalyzer setup for known failing tests
72+
if "test_gnoi_system_reboot_when_reboot_active" in request.node.nodeid or \
73+
"test_gnoi_system_reboot_status_immediately" in request.node.nodeid:
74+
logging.info("Skipping LogAnalyzer Setup for gnoi_system_reboot tests")
75+
yield
76+
return
77+
7178
# Analyze all the duts
7279
fail_test = not (request.config.getoption("--ignore_la_failure"))
7380
store_la_logs = request.config.getoption("--store_la_logs")
@@ -87,9 +94,12 @@ def loganalyzer(duthosts, request, log_rotate_modular_chassis):
8794

8895
yield analyzers
8996

90-
# Skip LogAnalyzer if case is skipped
97+
# Skip LogAnalyzer if case is skipped or if it's a known negative test
9198
if "rep_call" in request.node.__dict__ and request.node.rep_call.skipped or \
92-
"rep_setup" in request.node.__dict__ and request.node.rep_setup.skipped:
99+
"rep_setup" in request.node.__dict__ and request.node.rep_setup.skipped or \
100+
"test_gnoi_system_reboot_fail_invalid_method" in request.node.nodeid or \
101+
"test_gnoi_system_reboot_when_reboot_active" in request.node.nodeid or \
102+
"test_gnoi_system_reboot_status_immediately" in request.node.nodeid:
93103
return
94104
logging.info("Starting to analyse on all DUTs")
95105
parallel_run(analyze_logs, [analyzers, markers], {'fail_test': fail_test, 'store_la_logs': store_la_logs},

tests/gnmi/test_gnoi_system.py

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44

55
from .helper import gnoi_request
66
from tests.common.helpers.assertions import pytest_assert
7+
from tests.common.reboot import wait_for_startup
78
import re
89

910
pytestmark = [
1011
pytest.mark.topology('any')
1112
]
1213

14+
MAX_TIME_TO_REBOOT = 300
1315

1416
"""
1517
This module contains tests for the gNOI System API.
@@ -56,17 +58,42 @@ def test_gnoi_system_reboot_fail_invalid_method(duthosts, rand_one_dut_hostname,
5658
"""
5759
duthost = duthosts[rand_one_dut_hostname]
5860

61+
# Set flag to indicate that this test involves reboot
62+
duthost.host.options['skip_gnmi_check'] = True
63+
5964
# Trigger reboot with invalid method
60-
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 2}')
65+
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 99}')
6166
pytest_assert(ret != 0, "System.Reboot API did not report failure with invalid method")
6267

6368

69+
def test_gnoi_system_reboot_when_reboot_active(duthosts, rand_one_dut_hostname, localhost):
70+
"""
71+
Verify the gNOI System Reboot API fails if a reboot is already active.
72+
"""
73+
duthost = duthosts[rand_one_dut_hostname]
74+
75+
# Set flag to indicate that this test involves reboot
76+
duthost.host.options['skip_gnmi_check'] = True
77+
78+
# Trigger first reboot
79+
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 1}')
80+
pytest_assert(ret == 0, "System.Reboot API reported failure (rc = {}) with message: {}".format(ret, msg))
81+
logging.info("System.Reboot API returned msg: {}".format(msg))
82+
83+
# Trigger second reboot while the first one is still active
84+
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 1}')
85+
pytest_assert(ret != 0, "System.Reboot API did not report failure when reboot is already active")
86+
87+
6488
def test_gnoi_system_reboot_status_immediately(duthosts, rand_one_dut_hostname, localhost):
6589
"""
6690
Verify the gNOI System RebootStatus API returns the correct status immediately after reboot.
6791
"""
6892
duthost = duthosts[rand_one_dut_hostname]
6993

94+
# Set flag to indicate that this test involves reboot
95+
duthost.host.options['skip_gnmi_check'] = True
96+
7097
# Trigger reboot
7198
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 1, "message": "test"}')
7299
pytest_assert(ret == 0, "System.Reboot API reported failure (rc = {}) with message: {}".format(ret, msg))
@@ -87,6 +114,38 @@ def test_gnoi_system_reboot_status_immediately(duthosts, rand_one_dut_hostname,
87114
pytest_assert(msg_json["active"] is True, "System.RebootStatus API did not return active = true")
88115

89116

117+
def gnoi_system_reboot_status_after_startup(duthosts, rand_one_dut_hostname, localhost):
118+
"""
119+
Verify the gNOI System RebootStatus API returns the correct status after the device has started up.
120+
"""
121+
duthost = duthosts[rand_one_dut_hostname]
122+
123+
# Set flag to indicate that this test involves reboot
124+
duthost.host.options['skip_gnmi_check'] = True
125+
126+
# Trigger reboot
127+
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 1, "message": "test"}')
128+
pytest_assert(ret == 0, "System.Reboot API reported failure (rc = {}) with message: {}".format(ret, msg))
129+
logging.info("System.Reboot API returned msg: {}".format(msg))
130+
131+
# Wait for device to come back online
132+
wait_for_startup(duthost)
133+
134+
# Get reboot status
135+
ret, msg = gnoi_request(duthost, localhost, "RebootStatus", "")
136+
pytest_assert(ret == 0, "System.RebootStatus API reported failure (rc = {}) with message: {}".format(ret, msg))
137+
logging.info("System.RebootStatus API returned msg: {}".format(msg))
138+
# Message should contain a json substring like this
139+
# {"active":false,"wait":0,"when":0,"reason":"test","count":1,"method":1,"status":1}
140+
# Extract JSON part from the message
141+
msg_json = extract_first_json_substring(msg)
142+
if not msg_json:
143+
pytest.fail("Failed to extract JSON from System.RebootStatus API response")
144+
logging.info("Extracted JSON: {}".format(msg_json))
145+
pytest_assert("active" in msg_json, "System.RebootStatus API did not return active")
146+
pytest_assert(msg_json["active"] is False, "System.RebootStatus API did not return active = false")
147+
148+
90149
def extract_first_json_substring(s):
91150
"""
92151
Extract the first JSON substring from a given string.
@@ -95,12 +154,21 @@ def extract_first_json_substring(s):
95154
:return: The first JSON substring if found, otherwise None.
96155
"""
97156

98-
json_pattern = re.compile(r'\{.*?\}')
99-
match = json_pattern.search(s)
100-
if match:
101-
try:
102-
return json.loads(match.group())
103-
except json.JSONDecodeError:
104-
logging.error("Failed to parse JSON: {}".format(match.group()))
105-
return None
106-
return None
157+
start_index = s.find('{') # Find the first '{' in the string
158+
if start_index == -1:
159+
logging.error("No JSON found in response: {}".format(s))
160+
return None
161+
162+
json_str = s[start_index:] # Extract substring starting from '{'
163+
try:
164+
parsed_json = json.loads(json_str) # Attempt to parse the JSON
165+
# Handle cases where "status": {} is empty
166+
if "status" in parsed_json and parsed_json["status"] == {}:
167+
logging.warning("Replacing empty 'status' field with a default value.")
168+
parsed_json["status"] = {"unknown": "empty_status"}
169+
return parsed_json
170+
171+
except json.JSONDecodeError as e:
172+
logging.error("Failed to parse JSON: {} | Error: {}".format(json_str, e))
173+
return None
174+

0 commit comments

Comments
 (0)