Skip to content

Commit

Permalink
Merge branch 'reboot' into gnoi_reboot_tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Kanchana-HCLTech committed Jan 31, 2025
2 parents 6c553c3 + 9fcacf4 commit 24ed065
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 11 deletions.
12 changes: 11 additions & 1 deletion tests/common/plugins/loganalyzer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ def loganalyzer(duthosts, request, log_rotate_modular_chassis):
yield
return

# Skip LogAnalyzer setup for known failing tests
if "test_gnoi_system_reboot_when_reboot_active" in request.node.nodeid or \
"test_gnoi_system_reboot_status_immediately" in request.node.nodeid:
logging.info("Skipping LogAnalyzer Setup for gnoi_system_reboot tests")
yield
return

# Analyze all the duts
fail_test = not (request.config.getoption("--ignore_la_failure"))
store_la_logs = request.config.getoption("--store_la_logs")
Expand All @@ -89,7 +96,10 @@ def loganalyzer(duthosts, request, log_rotate_modular_chassis):

# Skip LogAnalyzer if case is skipped
if "rep_call" in request.node.__dict__ and request.node.rep_call.skipped or \
"rep_setup" in request.node.__dict__ and request.node.rep_setup.skipped:
"rep_setup" in request.node.__dict__ and request.node.rep_setup.skipped or \
"test_gnoi_system_reboot_fail_invalid_method" in request.node.nodeid or \
"test_gnoi_system_reboot_when_reboot_active" in request.node.nodeid or \
"test_gnoi_system_reboot_status_immediately" in request.node.nodeid:
return
logging.info("Starting to analyse on all DUTs")
parallel_run(analyze_logs, [analyzers, markers], {'fail_test': fail_test, 'store_la_logs': store_la_logs},
Expand Down
88 changes: 78 additions & 10 deletions tests/gnmi/test_gnoi_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

from .helper import gnoi_request
from tests.common.helpers.assertions import pytest_assert
from tests.common.reboot import wait_for_startup
import re

pytestmark = [
pytest.mark.topology('any')
]

MAX_TIME_TO_REBOOT = 300

"""
This module contains tests for the gNOI System API.
Expand Down Expand Up @@ -56,17 +58,42 @@ def test_gnoi_system_reboot_fail_invalid_method(duthosts, rand_one_dut_hostname,
"""
duthost = duthosts[rand_one_dut_hostname]

# Set flag to indicate that this test involves reboot
duthost.host.options['skip_gnmi_check'] = True

# Trigger reboot with invalid method
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 2}')
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 99}')
pytest_assert(ret != 0, "System.Reboot API did not report failure with invalid method")


def test_gnoi_system_reboot_when_reboot_active(duthosts, rand_one_dut_hostname, localhost):
"""
Verify the gNOI System Reboot API fails if a reboot is already active.
"""
duthost = duthosts[rand_one_dut_hostname]

# Set flag to indicate that this test involves reboot
duthost.host.options['skip_gnmi_check'] = True

# Trigger first reboot
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 1}')
pytest_assert(ret == 0, "System.Reboot API reported failure (rc = {}) with message: {}".format(ret, msg))
logging.info("System.Reboot API returned msg: {}".format(msg))

# Trigger second reboot while the first one is still active
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 1}')
pytest_assert(ret != 0, "System.Reboot API did not report failure when reboot is already active")


def test_gnoi_system_reboot_status_immediately(duthosts, rand_one_dut_hostname, localhost):
"""
Verify the gNOI System RebootStatus API returns the correct status immediately after reboot.
"""
duthost = duthosts[rand_one_dut_hostname]

# Set flag to indicate that this test involves reboot
duthost.host.options['skip_gnmi_check'] = True

# Trigger reboot
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 1, "message": "test"}')
pytest_assert(ret == 0, "System.Reboot API reported failure (rc = {}) with message: {}".format(ret, msg))
Expand All @@ -87,6 +114,38 @@ def test_gnoi_system_reboot_status_immediately(duthosts, rand_one_dut_hostname,
pytest_assert(msg_json["active"] is True, "System.RebootStatus API did not return active = true")


def gnoi_system_reboot_status_after_startup(duthosts, rand_one_dut_hostname, localhost):
"""
Verify the gNOI System RebootStatus API returns the correct status after the device has started up.
"""
duthost = duthosts[rand_one_dut_hostname]

# Set flag to indicate that this test involves reboot
duthost.host.options['skip_gnmi_check'] = True

# Trigger reboot
ret, msg = gnoi_request(duthost, localhost, "Reboot", '{"method": 1, "message": "test"}')
pytest_assert(ret == 0, "System.Reboot API reported failure (rc = {}) with message: {}".format(ret, msg))
logging.info("System.Reboot API returned msg: {}".format(msg))

# Wait for device to come back online
wait_for_startup(duthost)

# Get reboot status
ret, msg = gnoi_request(duthost, localhost, "RebootStatus", "")
pytest_assert(ret == 0, "System.RebootStatus API reported failure (rc = {}) with message: {}".format(ret, msg))
logging.info("System.RebootStatus API returned msg: {}".format(msg))
# Message should contain a json substring like this
# {"active":false,"wait":0,"when":0,"reason":"test","count":1,"method":1,"status":1}
# Extract JSON part from the message
msg_json = extract_first_json_substring(msg)
if not msg_json:
pytest.fail("Failed to extract JSON from System.RebootStatus API response")
logging.info("Extracted JSON: {}".format(msg_json))
pytest_assert("active" in msg_json, "System.RebootStatus API did not return active")
pytest_assert(msg_json["active"] is False, "System.RebootStatus API did not return active = false")


def extract_first_json_substring(s):
"""
Extract the first JSON substring from a given string.
Expand All @@ -95,12 +154,21 @@ def extract_first_json_substring(s):
:return: The first JSON substring if found, otherwise None.
"""

json_pattern = re.compile(r'\{.*?\}')
match = json_pattern.search(s)
if match:
try:
return json.loads(match.group())
except json.JSONDecodeError:
logging.error("Failed to parse JSON: {}".format(match.group()))
return None
return None
start_index = s.find('{') # Find the first '{' in the string
if start_index == -1:
logging.error("No JSON found in response: {}".format(s))
return None

json_str = s[start_index:] # Extract substring starting from '{'
try:
parsed_json = json.loads(json_str) # Attempt to parse the JSON
# Handle cases where "status": {} is empty
if "status" in parsed_json and parsed_json["status"] == {}:
logging.warning("Replacing empty 'status' field with a default value.")
parsed_json["status"] = {"unknown": "empty_status"}
return parsed_json

except json.JSONDecodeError as e:
logging.error("Failed to parse JSON: {} | Error: {}".format(json_str, e))
return None

0 comments on commit 24ed065

Please sign in to comment.