From df597bda2e33707e01a3532e3b0ddf0de3fee7a0 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Thu, 10 Apr 2025 22:46:08 -0700 Subject: [PATCH 01/61] Fixed issue #22138 --- config/chassis_modules.py | 84 ++++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/config/chassis_modules.py b/config/chassis_modules.py index 20b8c9093a..3b447e6bdf 100755 --- a/config/chassis_modules.py +++ b/config/chassis_modules.py @@ -6,9 +6,10 @@ import subprocess import utilities_common.cli as clicommon from utilities_common.chassis import is_smartswitch, get_all_dpus +from datetime import datetime, timedelta TIMEOUT_SECS = 10 - +TRANSITION_TIMEOUT = timedelta(seconds=240) # 4 minutes # # 'chassis_modules' group ('config chassis_modules ...') @@ -35,6 +36,34 @@ def get_config_module_state(db, chassis_module_name): else: return fvs['admin_status'] +def get_state_transition_in_progress(db, chassis_module_name): + config_db = db.cfgdb + fvs = config_db.get_entry('CHASSIS_MODULE', chassis_module_name) + return fvs.get('state_transition_in_progress', 'False') if fvs else 'False' + +def set_state_transition_in_progress(db, chassis_module_name, value): + config_db = db.cfgdb + entry = config_db.get_entry('CHASSIS_MODULE', chassis_module_name) or {} + entry['state_transition_in_progress'] = value + if value == 'True': + entry['transition_start_time'] = datetime.utcnow().isoformat() + else: + entry.pop('transition_start_time', None) + config_db.set_entry('CHASSIS_MODULE', chassis_module_name, entry) + +def is_transition_timed_out(db, chassis_module_name): + config_db = db.cfgdb + fvs = config_db.get_entry('CHASSIS_MODULE', chassis_module_name) + if not fvs: + return False + start_time_str = fvs.get('transition_start_time') + if not start_time_str: + return False + try: + start_time = datetime.fromisoformat(start_time_str) + except ValueError: + return False + return datetime.utcnow() - start_time > TRANSITION_TIMEOUT # # Name: check_config_module_state_with_timeout @@ -116,20 +145,33 @@ def shutdown_chassis_module(db, chassis_module_name): config_db = db.cfgdb ctx = click.get_current_context() - if not chassis_module_name.startswith("SUPERVISOR") and \ - not chassis_module_name.startswith("LINE-CARD") and \ - not chassis_module_name.startswith("FABRIC-CARD") and \ - not chassis_module_name.startswith("DPU"): - ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD', 'FABRIC-CARD', 'DPU'") + if not chassis_module_name.startswith(("SUPERVISOR", "LINE-CARD", "FABRIC-CARD", "DPU")): + ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD', 'FABRIC-CARD', or 'DPU'") - # To avoid duplicate operation if get_config_module_state(db, chassis_module_name) == 'down': - click.echo("Module {} is already in down state".format(chassis_module_name)) + click.echo(f"Module {chassis_module_name} is already in down state") return - click.echo("Shutting down chassis module {}".format(chassis_module_name)) - fvs = {'admin_status': 'down'} - config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs) + if is_smartswitch(): + if get_state_transition_in_progress(db, chassis_module_name) == 'True': + if is_transition_timed_out(db, chassis_module_name): + set_state_transition_in_progress(db, chassis_module_name, 'False') + click.echo(f"Previous transition for module {chassis_module_name} timed out. Proceeding with shutdown.") + else: + click.echo(f"Module {chassis_module_name} state transition is already in progress") + return + + click.echo(f"Shutting down chassis module {chassis_module_name}") + fvs = { + 'admin_status': 'down', + 'state_transition_in_progress': 'True', + 'transition_start_time': datetime.utcnow().isoformat() + } + config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs) + else: + click.echo(f"Shutting down chassis module {chassis_module_name}") + config_db.set_entry('CHASSIS_MODULE', chassis_module_name, {'admin_status': 'down'}) + if chassis_module_name.startswith("FABRIC-CARD"): if not check_config_module_state_with_timeout(ctx, db, chassis_module_name, 'down'): fabric_module_set_admin_status(db, chassis_module_name, 'down') @@ -149,16 +191,28 @@ def startup_chassis_module(db, chassis_module_name): config_db = db.cfgdb ctx = click.get_current_context() - # To avoid duplicate operation if get_config_module_state(db, chassis_module_name) == 'up': - click.echo("Module {} is already set to up state".format(chassis_module_name)) + click.echo(f"Module {chassis_module_name} is already set to up state") return - click.echo("Starting up chassis module {}".format(chassis_module_name)) if is_smartswitch(): - fvs = {'admin_status': 'up'} + if get_state_transition_in_progress(db, chassis_module_name) == 'True': + if is_transition_timed_out(db, chassis_module_name): + set_state_transition_in_progress(db, chassis_module_name, 'False') + click.echo(f"Previous transition for module {chassis_module_name} timed out. Proceeding with startup.") + else: + click.echo(f"Module {chassis_module_name} state transition is already in progress") + return + + click.echo(f"Starting up chassis module {chassis_module_name}") + fvs = { + 'admin_status': 'up', + 'state_transition_in_progress': 'True', + 'transition_start_time': datetime.utcnow().isoformat() + } config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs) else: + click.echo(f"Starting up chassis module {chassis_module_name}") config_db.set_entry('CHASSIS_MODULE', chassis_module_name, None) if chassis_module_name.startswith("FABRIC-CARD"): From 1ac41991ae0081770b457708f9991c692a8c3841 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Fri, 11 Apr 2025 06:34:04 -0700 Subject: [PATCH 02/61] Resolved SA errors --- config/chassis_modules.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/chassis_modules.py b/config/chassis_modules.py index 3b447e6bdf..b8c2fca90b 100755 --- a/config/chassis_modules.py +++ b/config/chassis_modules.py @@ -36,11 +36,13 @@ def get_config_module_state(db, chassis_module_name): else: return fvs['admin_status'] + def get_state_transition_in_progress(db, chassis_module_name): config_db = db.cfgdb fvs = config_db.get_entry('CHASSIS_MODULE', chassis_module_name) return fvs.get('state_transition_in_progress', 'False') if fvs else 'False' + def set_state_transition_in_progress(db, chassis_module_name, value): config_db = db.cfgdb entry = config_db.get_entry('CHASSIS_MODULE', chassis_module_name) or {} @@ -51,6 +53,7 @@ def set_state_transition_in_progress(db, chassis_module_name, value): entry.pop('transition_start_time', None) config_db.set_entry('CHASSIS_MODULE', chassis_module_name, entry) + def is_transition_timed_out(db, chassis_module_name): config_db = db.cfgdb fvs = config_db.get_entry('CHASSIS_MODULE', chassis_module_name) From c111cfcc1718764bec5284d02cbf58eb8a0b60fb Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 10:50:43 -0700 Subject: [PATCH 03/61] Adding coverage --- tests/chassis_modules_test.py | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index f59341a487..89aa261219 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -441,6 +441,49 @@ def test_show_and_verify_system_lags_output_lc4(self): assert return_code == 0 assert result == show_chassis_system_lags_output_lc4 + @mock.patch('config.main.is_smartswitch', return_value=True) + def test_shutdown_with_timed_out_transition(self, mock_smartswitch): + runner = CliRunner() + db = Db() + + # Simulate a timed-out state transition + transition_start = datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=10) + db.cfgdb.set_entry('CHASSIS_MODULE', 'LINE-CARD0', { + 'state_transition_in_progress': 'True', + 'transition_start_time': transition_start.isoformat() + }) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["LINE-CARD0"], + obj=db + ) + + print(result.output) + assert "timed out" in result.output + assert result.exit_code == 0 + + @mock.patch('config.main.is_smartswitch', return_value=True) + def test_shutdown_with_transition_in_progress_not_timed_out(self, mock_smartswitch): + runner = CliRunner() + db = Db() + + # Simulate a state transition still in progress and not timed out + db.cfgdb.set_entry('CHASSIS_MODULE', 'LINE-CARD0', { + 'state_transition_in_progress': 'True', + 'transition_start_time': datetime.utcnow().isoformat() + }) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["LINE-CARD0"], + obj=db + ) + + print(result.output) + assert "state transition is already in progress" in result.output + assert result.exit_code == 0 + @classmethod def teardown_class(cls): print("TEARDOWN") From 0df04c8bdec59eb6c0ff62fd6855c1c0ac619b7f Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 11:41:52 -0700 Subject: [PATCH 04/61] Adding coverage --- tests/chassis_modules_test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 89aa261219..704e8e6068 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -1,15 +1,19 @@ import sys import os from click.testing import CliRunner +from datetime import datetime, timedelta import show.main as show import config.main as config import tests.mock_tables.dbconnector from utilities_common.db import Db +from utilities_common.chassis import is_smartswitch from .utils import get_result_and_return_code from unittest import mock sys.modules['clicommon'] = mock.Mock() +TRANSITION_TIMEOUT = timedelta(seconds=60) + show_linecard0_shutdown_output="""\ LINE-CARD0 line-card 1 Empty down LC1000101 """ @@ -441,7 +445,7 @@ def test_show_and_verify_system_lags_output_lc4(self): assert return_code == 0 assert result == show_chassis_system_lags_output_lc4 - @mock.patch('config.main.is_smartswitch', return_value=True) + @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) def test_shutdown_with_timed_out_transition(self, mock_smartswitch): runner = CliRunner() db = Db() @@ -463,7 +467,7 @@ def test_shutdown_with_timed_out_transition(self, mock_smartswitch): assert "timed out" in result.output assert result.exit_code == 0 - @mock.patch('config.main.is_smartswitch', return_value=True) + @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) def test_shutdown_with_transition_in_progress_not_timed_out(self, mock_smartswitch): runner = CliRunner() db = Db() From f42edea3f934cfef1db1e41ac3ab858f687530f8 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 11:44:32 -0700 Subject: [PATCH 05/61] Adding coverage --- tests/chassis_modules_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 704e8e6068..d9f233fb9f 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -7,7 +7,6 @@ import config.main as config import tests.mock_tables.dbconnector from utilities_common.db import Db -from utilities_common.chassis import is_smartswitch from .utils import get_result_and_return_code from unittest import mock sys.modules['clicommon'] = mock.Mock() From 2b5b87f0f40fee5cc6f702ef21025b4e7899c271 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 14:14:49 -0700 Subject: [PATCH 06/61] Adding coverage --- tests/chassis_modules_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index d9f233fb9f..340e6759b4 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -451,14 +451,14 @@ def test_shutdown_with_timed_out_transition(self, mock_smartswitch): # Simulate a timed-out state transition transition_start = datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=10) - db.cfgdb.set_entry('CHASSIS_MODULE', 'LINE-CARD0', { + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { 'state_transition_in_progress': 'True', 'transition_start_time': transition_start.isoformat() }) result = runner.invoke( config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["LINE-CARD0"], + ["DPU0"], obj=db ) @@ -472,14 +472,14 @@ def test_shutdown_with_transition_in_progress_not_timed_out(self, mock_smartswit db = Db() # Simulate a state transition still in progress and not timed out - db.cfgdb.set_entry('CHASSIS_MODULE', 'LINE-CARD0', { + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { 'state_transition_in_progress': 'True', 'transition_start_time': datetime.utcnow().isoformat() }) result = runner.invoke( config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["LINE-CARD0"], + ["DPU0"], obj=db ) From 051753cb2c567a3c12dc57f56de750a954d5db8b Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 15:24:44 -0700 Subject: [PATCH 07/61] Adding coverage --- tests/chassis_modules_test.py | 61 +++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 340e6759b4..62325d523e 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -445,19 +445,21 @@ def test_show_and_verify_system_lags_output_lc4(self): assert result == show_chassis_system_lags_output_lc4 @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) - def test_shutdown_with_timed_out_transition(self, mock_smartswitch): + @mock.patch('utilities_common.chassis.get_transition_start_time') + def test_shutdown_with_timed_out_transition(mock_get_time, mock_smartswitch): runner = CliRunner() db = Db() - # Simulate a timed-out state transition - transition_start = datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=10) + # Simulate a timeout (transition start is in the past beyond timeout) + mock_get_time.return_value = datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=10) + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { 'state_transition_in_progress': 'True', - 'transition_start_time': transition_start.isoformat() + 'admin_status': 'down' }) result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], + config.commands["chassis"].commands["modules"].commands["shutdown"], ["DPU0"], obj=db ) @@ -467,18 +469,21 @@ def test_shutdown_with_timed_out_transition(self, mock_smartswitch): assert result.exit_code == 0 @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) - def test_shutdown_with_transition_in_progress_not_timed_out(self, mock_smartswitch): + @mock.patch('utilities_common.chassis.get_transition_start_time') + def test_shutdown_with_transition_in_progress_not_timed_out(mock_get_time, mock_smartswitch): runner = CliRunner() db = Db() - # Simulate a state transition still in progress and not timed out + # Simulate a recent transition, still within the timeout + mock_get_time.return_value = datetime.utcnow() - timedelta(seconds=5) + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { 'state_transition_in_progress': 'True', - 'transition_start_time': datetime.utcnow().isoformat() + 'admin_status': 'down' }) result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], + config.commands["chassis"].commands["modules"].commands["shutdown"], ["DPU0"], obj=db ) @@ -487,6 +492,44 @@ def test_shutdown_with_transition_in_progress_not_timed_out(self, mock_smartswit assert "state transition is already in progress" in result.output assert result.exit_code == 0 + @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) + def test_shutdown_when_no_transition_in_progress(mock_smartswitch): + runner = CliRunner() + db = Db() + + # Clean shutdown request with no transition + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up' + }) + + result = runner.invoke( + config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + + print(result.output) + assert "Shutdown request initiated" in result.output or result.exit_code == 0 + + @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) + def test_startup_when_no_transition_in_progress(mock_smartswitch): + runner = CliRunner() + db = Db() + + # Clean shutdown request with no transition + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'down' + }) + + result = runner.invoke( + config.commands["chassis"].commands["modules"].commands["startup"], + ["DPU0"], + obj=db + ) + + print(result.output) + assert "Startup request initiated" in result.output or result.exit_code == 0 + @classmethod def teardown_class(cls): print("TEARDOWN") From 32fad326303b18edcf3c150df230b3548054e3aa Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 16:45:12 -0700 Subject: [PATCH 08/61] Adding coverage --- tests/chassis_modules_test.py | 81 +++-------------------------------- 1 file changed, 6 insertions(+), 75 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 62325d523e..73ac89be9d 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -444,43 +444,10 @@ def test_show_and_verify_system_lags_output_lc4(self): assert return_code == 0 assert result == show_chassis_system_lags_output_lc4 - @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) - @mock.patch('utilities_common.chassis.get_transition_start_time') - def test_shutdown_with_timed_out_transition(mock_get_time, mock_smartswitch): - runner = CliRunner() + @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) + def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): db = Db() - - # Simulate a timeout (transition start is in the past beyond timeout) - mock_get_time.return_value = datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=10) - - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'state_transition_in_progress': 'True', - 'admin_status': 'down' - }) - - result = runner.invoke( - config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - - print(result.output) - assert "timed out" in result.output - assert result.exit_code == 0 - - @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) - @mock.patch('utilities_common.chassis.get_transition_start_time') - def test_shutdown_with_transition_in_progress_not_timed_out(mock_get_time, mock_smartswitch): runner = CliRunner() - db = Db() - - # Simulate a recent transition, still within the timeout - mock_get_time.return_value = datetime.utcnow() - timedelta(seconds=5) - - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'state_transition_in_progress': 'True', - 'admin_status': 'down' - }) result = runner.invoke( config.commands["chassis"].commands["modules"].commands["shutdown"], @@ -488,48 +455,12 @@ def test_shutdown_with_transition_in_progress_not_timed_out(mock_get_time, mock_ obj=db ) - print(result.output) - assert "state transition is already in progress" in result.output + fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + assert fvs['admin_status'] == 'down' + assert fvs['state_transition_in_progress'] == 'True' + assert 'transition_start_time' in fvs assert result.exit_code == 0 - @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) - def test_shutdown_when_no_transition_in_progress(mock_smartswitch): - runner = CliRunner() - db = Db() - - # Clean shutdown request with no transition - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up' - }) - - result = runner.invoke( - config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - - print(result.output) - assert "Shutdown request initiated" in result.output or result.exit_code == 0 - - @mock.patch('utilities_common.chassis.is_smartswitch', return_value=True) - def test_startup_when_no_transition_in_progress(mock_smartswitch): - runner = CliRunner() - db = Db() - - # Clean shutdown request with no transition - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'down' - }) - - result = runner.invoke( - config.commands["chassis"].commands["modules"].commands["startup"], - ["DPU0"], - obj=db - ) - - print(result.output) - assert "Startup request initiated" in result.output or result.exit_code == 0 - @classmethod def teardown_class(cls): print("TEARDOWN") From fc9338c0235d19b7eb65bfa490ae35cacb1ea699 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 17:05:48 -0700 Subject: [PATCH 09/61] Adding coverage --- tests/chassis_modules_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 73ac89be9d..86264046e6 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -1,7 +1,6 @@ import sys import os from click.testing import CliRunner -from datetime import datetime, timedelta import show.main as show import config.main as config From 7ef8186efe03fcaae383ff72fb48a30ec5601b55 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 17:11:01 -0700 Subject: [PATCH 10/61] Adding coverage --- tests/chassis_modules_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 86264046e6..54e6d841bf 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -10,8 +10,6 @@ from unittest import mock sys.modules['clicommon'] = mock.Mock() -TRANSITION_TIMEOUT = timedelta(seconds=60) - show_linecard0_shutdown_output="""\ LINE-CARD0 line-card 1 Empty down LC1000101 """ From ed3547776c6515479c6a1aecaf648d21df003691 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 17:43:00 -0700 Subject: [PATCH 11/61] Adding coverage --- tests/chassis_modules_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 54e6d841bf..9930348db1 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -447,7 +447,7 @@ def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): runner = CliRunner() result = runner.invoke( - config.commands["chassis"].commands["modules"].commands["shutdown"], + config.config.commands["chassis"].commands["modules"].commands["shutdown"], ["DPU0"], obj=db ) From 7ee216dff4d034d3cb478a61e967602412b971ad Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 18:21:52 -0700 Subject: [PATCH 12/61] Adding coverage --- tests/chassis_modules_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 9930348db1..97672e85cb 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -446,6 +446,11 @@ def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): db = Db() runner = CliRunner() + # Prepopulate with a module in "up" state to trigger shutdown logic + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up' + }) + result = runner.invoke( config.config.commands["chassis"].commands["modules"].commands["shutdown"], ["DPU0"], From 5a272455c07d783d76c97e45e2a842d8967182f5 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 18:57:23 -0700 Subject: [PATCH 13/61] Adding coverage --- tests/chassis_modules_test.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 97672e85cb..efea5bc071 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -442,26 +442,32 @@ def test_show_and_verify_system_lags_output_lc4(self): assert result == show_chassis_system_lags_output_lc4 @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) - def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): + def test_shutdown_triggers_transition_tracking(mock_smartswitch): db = Db() runner = CliRunner() - # Prepopulate with a module in "up" state to trigger shutdown logic + # Ensure module is not already 'down' + # and no transition is in progress db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up' + 'admin_status': 'up', + 'state_transition_in_progress': 'False' }) result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], + config.commands["chassis"].commands["modules"].commands["shutdown"], ["DPU0"], obj=db ) + print("CLI Output:", result.output) + assert result.exit_code == 0, "CLI failed unexpectedly" + fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') - assert fvs['admin_status'] == 'down' - assert fvs['state_transition_in_progress'] == 'True' + + # Check that shutdown updated the DB as expected + assert fvs.get('admin_status') == 'down' + assert fvs.get('state_transition_in_progress') == 'True' assert 'transition_start_time' in fvs - assert result.exit_code == 0 @classmethod def teardown_class(cls): From 1d962632078be3f6681875981bce70852140bf2b Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 19:40:07 -0700 Subject: [PATCH 14/61] Adding coverage --- tests/chassis_modules_test.py | 52 +++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index efea5bc071..e4c7dc6396 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -6,6 +6,8 @@ import config.main as config import tests.mock_tables.dbconnector from utilities_common.db import Db +from utilities_common.chassis import TRANSITION_TIMEOUT + from .utils import get_result_and_return_code from unittest import mock sys.modules['clicommon'] = mock.Mock() @@ -442,7 +444,7 @@ def test_show_and_verify_system_lags_output_lc4(self): assert result == show_chassis_system_lags_output_lc4 @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) - def test_shutdown_triggers_transition_tracking(mock_smartswitch): + def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): db = Db() runner = CliRunner() @@ -454,7 +456,7 @@ def test_shutdown_triggers_transition_tracking(mock_smartswitch): }) result = runner.invoke( - config.commands["chassis"].commands["modules"].commands["shutdown"], + config.config.commands["chassis"].commands["modules"].commands["shutdown"], ["DPU0"], obj=db ) @@ -469,6 +471,52 @@ def test_shutdown_triggers_transition_tracking(mock_smartswitch): assert fvs.get('state_transition_in_progress') == 'True' assert 'transition_start_time' in fvs + @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) + def test_shutdown_skips_if_transition_in_progress_not_timed_out(self, mock_smartswitch): + db = Db() + runner = CliRunner() + + transition_start_time = datetime.utcnow().isoformat() + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up', + 'state_transition_in_progress': 'True', + 'transition_start_time': transition_start_time + }) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + + assert "already in progress" in result.output + assert result.exit_code == 0 + + @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) + def test_shutdown_resets_if_transition_timed_out(self, mock_smartswitch): + db = Db() + runner = CliRunner() + + timeout_start = (datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=5)).isoformat() + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up', + 'state_transition_in_progress': 'True', + 'transition_start_time': timeout_start + }) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + + fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + assert result.exit_code == 0 + assert fvs.get('admin_status') == 'down' + assert fvs.get('state_transition_in_progress') == 'True' + assert 'transition_start_time' in fvs + assert "timed out" in result.output + @classmethod def teardown_class(cls): print("TEARDOWN") From 02450392d1a91be840d6b826f52a903e766b023a Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 19:59:42 -0700 Subject: [PATCH 15/61] Adding coverage --- tests/chassis_modules_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index e4c7dc6396..a0a4a2b49b 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -1,6 +1,7 @@ import sys import os from click.testing import CliRunner +from datetime import datetime, timedelta import show.main as show import config.main as config From 628bdebd56d198fd63bf2128d458489dc8538d0b Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 20:15:23 -0700 Subject: [PATCH 16/61] Adding coverage --- tests/chassis_modules_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index a0a4a2b49b..258c45f045 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -7,8 +7,7 @@ import config.main as config import tests.mock_tables.dbconnector from utilities_common.db import Db -from utilities_common.chassis import TRANSITION_TIMEOUT - +from config.chassis_modules import TRANSITION_TIMEOUT from .utils import get_result_and_return_code from unittest import mock sys.modules['clicommon'] = mock.Mock() From bb1f45cc9549bfb6a8694f76aec1d98bd4cdafe9 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 20:50:44 -0700 Subject: [PATCH 17/61] Adding coverage --- tests/chassis_modules_test.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 258c45f045..6d102f3f08 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -137,6 +137,27 @@ def mock_run_command_side_effect(*args, **kwargs): return '', 0 +class FakeConfigDBConnector: + def __init__(self): + self.tables = {} + + def set_entry(self, table, key, value): + if table not in self.tables: + self.tables[table] = {} + self.tables[table][key] = value + + def get_entry(self, table, key): + return self.tables.get(table, {}).get(key, {}) + + def get_table(self, table): + return self.tables.get(table, {}) + + +class FakeDb: + def __init__(self): + self.cfg_db = FakeConfigDBConnector() + + class TestChassisModules(object): @classmethod def setup_class(cls): @@ -445,7 +466,7 @@ def test_show_and_verify_system_lags_output_lc4(self): @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): - db = Db() + db = FakeDb() runner = CliRunner() # Ensure module is not already 'down' @@ -473,7 +494,7 @@ def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) def test_shutdown_skips_if_transition_in_progress_not_timed_out(self, mock_smartswitch): - db = Db() + db = FakeDb() runner = CliRunner() transition_start_time = datetime.utcnow().isoformat() @@ -494,7 +515,7 @@ def test_shutdown_skips_if_transition_in_progress_not_timed_out(self, mock_smart @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) def test_shutdown_resets_if_transition_timed_out(self, mock_smartswitch): - db = Db() + db = FakeDb() runner = CliRunner() timeout_start = (datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=5)).isoformat() From 8a03b9cd27e649972d7c686005d3754546bfe712 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 21:01:35 -0700 Subject: [PATCH 18/61] Adding coverage --- tests/chassis_modules_test.py | 50 ----------------------------------- 1 file changed, 50 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 6d102f3f08..7ad4c32432 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -469,8 +469,6 @@ def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): db = FakeDb() runner = CliRunner() - # Ensure module is not already 'down' - # and no transition is in progress db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { 'admin_status': 'up', 'state_transition_in_progress': 'False' @@ -483,60 +481,12 @@ def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): ) print("CLI Output:", result.output) - assert result.exit_code == 0, "CLI failed unexpectedly" - - fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') - - # Check that shutdown updated the DB as expected - assert fvs.get('admin_status') == 'down' - assert fvs.get('state_transition_in_progress') == 'True' - assert 'transition_start_time' in fvs - - @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) - def test_shutdown_skips_if_transition_in_progress_not_timed_out(self, mock_smartswitch): - db = FakeDb() - runner = CliRunner() - - transition_start_time = datetime.utcnow().isoformat() - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up', - 'state_transition_in_progress': 'True', - 'transition_start_time': transition_start_time - }) - - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - - assert "already in progress" in result.output assert result.exit_code == 0 - @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) - def test_shutdown_resets_if_transition_timed_out(self, mock_smartswitch): - db = FakeDb() - runner = CliRunner() - - timeout_start = (datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=5)).isoformat() - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up', - 'state_transition_in_progress': 'True', - 'transition_start_time': timeout_start - }) - - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') - assert result.exit_code == 0 assert fvs.get('admin_status') == 'down' assert fvs.get('state_transition_in_progress') == 'True' assert 'transition_start_time' in fvs - assert "timed out" in result.output @classmethod def teardown_class(cls): From 0bf4d122cc24a8803c4fad58ac5fe05a03672212 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 21:04:08 -0700 Subject: [PATCH 19/61] Adding coverage --- tests/chassis_modules_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 7ad4c32432..5b65c26bc0 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -1,7 +1,7 @@ import sys import os from click.testing import CliRunner -from datetime import datetime, timedelta +# from datetime import datetime, timedelta import show.main as show import config.main as config From 9655381be6d408f421fee9481eb5cc4940a827ef Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 21:06:42 -0700 Subject: [PATCH 20/61] Adding coverage --- tests/chassis_modules_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 5b65c26bc0..9b136bc17d 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -2,12 +2,12 @@ import os from click.testing import CliRunner # from datetime import datetime, timedelta +# from config.chassis_modules import TRANSITION_TIMEOUT import show.main as show import config.main as config import tests.mock_tables.dbconnector from utilities_common.db import Db -from config.chassis_modules import TRANSITION_TIMEOUT from .utils import get_result_and_return_code from unittest import mock sys.modules['clicommon'] = mock.Mock() From 9f5d102d8d6470fd2083c43f660358413917ff06 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 21:56:16 -0700 Subject: [PATCH 21/61] Adding coverage --- tests/chassis_modules_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 9b136bc17d..4be52dacff 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -155,7 +155,7 @@ def get_table(self, table): class FakeDb: def __init__(self): - self.cfg_db = FakeConfigDBConnector() + self.cfgdb = FakeConfigDBConnector() class TestChassisModules(object): From f137859d3710ba56dfaeb5508021ec599c71f0ae Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 22:26:21 -0700 Subject: [PATCH 22/61] Adding coverage --- tests/chassis_modules_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 4be52dacff..bc21b72ea7 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -469,9 +469,9 @@ def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): db = FakeDb() runner = CliRunner() + # Initial state: module is up, no transition yet db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up', - 'state_transition_in_progress': 'False' + 'admin_status': 'up' }) result = runner.invoke( @@ -484,6 +484,7 @@ def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): assert result.exit_code == 0 fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + print(f"Final state: {fvs}") assert fvs.get('admin_status') == 'down' assert fvs.get('state_transition_in_progress') == 'True' assert 'transition_start_time' in fvs From be28cdf867e09e444d6711a6b0821fad3c46a33a Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 22:58:49 -0700 Subject: [PATCH 23/61] Adding coverage --- tests/chassis_modules_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index bc21b72ea7..7242a01102 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -465,11 +465,11 @@ def test_show_and_verify_system_lags_output_lc4(self): assert result == show_chassis_system_lags_output_lc4 @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) - def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): + @mock.patch("config.chassis_modules.get_config_module_state", return_value='up') + def test_shutdown_triggers_transition_tracking(self, mock_state, mock_smartswitch): db = FakeDb() runner = CliRunner() - # Initial state: module is up, no transition yet db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { 'admin_status': 'up' }) @@ -484,7 +484,6 @@ def test_shutdown_triggers_transition_tracking(self, mock_smartswitch): assert result.exit_code == 0 fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') - print(f"Final state: {fvs}") assert fvs.get('admin_status') == 'down' assert fvs.get('state_transition_in_progress') == 'True' assert 'transition_start_time' in fvs From 094b75175e367f3c35e74a8633e8d49d1160799d Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 23:41:16 -0700 Subject: [PATCH 24/61] Adding coverage --- tests/chassis_modules_test.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 7242a01102..2c652193a3 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -466,7 +466,36 @@ def test_show_and_verify_system_lags_output_lc4(self): @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) @mock.patch("config.chassis_modules.get_config_module_state", return_value='up') - def test_shutdown_triggers_transition_tracking(self, mock_state, mock_smartswitch): + def test_shutdown_triggers_transition_tracking_test(self, mock_state, mock_smartswitch): + db = FakeDb() + runner = CliRunner() + + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up' + }) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + + print("CLI Output:", result.output) + assert result.exit_code == 0 + + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], ["DPU0"], obj=db) + print(result.exit_code) + print(result.output) + result_lines = result.output.strip('\n').split('\n') + assert result.exit_code == 0 + header_lines = 2 + result_out = " ".join((result_lines[header_lines]).split()) + assert "DPU0" in result_out and "down" in result_out.lower() + +def test_shutdown_triggers_transition_tracking(self): + with mock.patch("utilities_common.chassis.is_smartswitch", return_value=True), \ + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + db = FakeDb() runner = CliRunner() From 86ec6b17f21b66b1551c8bed7be8fafe89b7134c Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 23:45:33 -0700 Subject: [PATCH 25/61] Adding coverage --- tests/chassis_modules_test.py | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 2c652193a3..f8a6fe00e3 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -492,30 +492,30 @@ def test_shutdown_triggers_transition_tracking_test(self, mock_state, mock_smart result_out = " ".join((result_lines[header_lines]).split()) assert "DPU0" in result_out and "down" in result_out.lower() -def test_shutdown_triggers_transition_tracking(self): - with mock.patch("utilities_common.chassis.is_smartswitch", return_value=True), \ - mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - - db = FakeDb() - runner = CliRunner() + def test_shutdown_triggers_transition_tracking(self): + with mock.patch("utilities_common.chassis.is_smartswitch", return_value=True), \ + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + + db = FakeDb() + runner = CliRunner() - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up' - }) + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up' + }) - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) - print("CLI Output:", result.output) - assert result.exit_code == 0 + print("CLI Output:", result.output) + assert result.exit_code == 0 - fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') - assert fvs.get('admin_status') == 'down' - assert fvs.get('state_transition_in_progress') == 'True' - assert 'transition_start_time' in fvs + fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + assert fvs.get('admin_status') == 'down' + assert fvs.get('state_transition_in_progress') == 'True' + assert 'transition_start_time' in fvs @classmethod def teardown_class(cls): From f20a880087c5d8c0b4fbf25e8bff95cd48cb7579 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Mon, 14 Apr 2025 23:47:36 -0700 Subject: [PATCH 26/61] Adding coverage --- tests/chassis_modules_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index f8a6fe00e3..45ba7118bd 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -494,8 +494,8 @@ def test_shutdown_triggers_transition_tracking_test(self, mock_state, mock_smart def test_shutdown_triggers_transition_tracking(self): with mock.patch("utilities_common.chassis.is_smartswitch", return_value=True), \ - mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + db = FakeDb() runner = CliRunner() From 2e2c79e98341aaf4939c26c0e04fc58300486037 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 07:30:14 -0700 Subject: [PATCH 27/61] Adding coverage --- tests/chassis_modules_test.py | 49 ++++++++--------------------------- 1 file changed, 11 insertions(+), 38 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 45ba7118bd..4dd29acc90 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -142,9 +142,7 @@ def __init__(self): self.tables = {} def set_entry(self, table, key, value): - if table not in self.tables: - self.tables[table] = {} - self.tables[table][key] = value + self.tables.setdefault(table, {})[key] = value def get_entry(self, table, key): return self.tables.get(table, {}).get(key, {}) @@ -464,9 +462,9 @@ def test_show_and_verify_system_lags_output_lc4(self): assert return_code == 0 assert result == show_chassis_system_lags_output_lc4 - @mock.patch("utilities_common.chassis.is_smartswitch", return_value=True) + @mock.patch("sonic_py_common.device_info.is_smartswitch", return_value=True) @mock.patch("config.chassis_modules.get_config_module_state", return_value='up') - def test_shutdown_triggers_transition_tracking_test(self, mock_state, mock_smartswitch): + def test_shutdown_triggers_transition_tracking(self, mock_state, mock_smartswitch): db = FakeDb() runner = CliRunner() @@ -480,42 +478,17 @@ def test_shutdown_triggers_transition_tracking_test(self, mock_state, mock_smart obj=db ) - print("CLI Output:", result.output) + print("Ram CLI Output:", result.output) assert result.exit_code == 0 - result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], ["DPU0"], obj=db) - print(result.exit_code) - print(result.output) - result_lines = result.output.strip('\n').split('\n') - assert result.exit_code == 0 - header_lines = 2 - result_out = " ".join((result_lines[header_lines]).split()) - assert "DPU0" in result_out and "down" in result_out.lower() - - def test_shutdown_triggers_transition_tracking(self): - with mock.patch("utilities_common.chassis.is_smartswitch", return_value=True), \ - mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - - db = FakeDb() - runner = CliRunner() - - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up' - }) - - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - - print("CLI Output:", result.output) - assert result.exit_code == 0 + assert result.exit_code == 0, f"CLI failed: {result.output}" - fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') - assert fvs.get('admin_status') == 'down' - assert fvs.get('state_transition_in_progress') == 'True' - assert 'transition_start_time' in fvs + # Verify CONFIG_DB is correctly updated + fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") + print("Ram fvs:{}".format(fvs)) + assert fvs.get("admin_status") == "down" + assert fvs.get("state_transition_in_progress") == "True" + assert "transition_start_time" in fvs @classmethod def teardown_class(cls): From 3e8e5d5345c1ff70c90b50a09d9c982676a6da7a Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 08:02:46 -0700 Subject: [PATCH 28/61] Adding coverage --- tests/chassis_modules_test.py | 42 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 4dd29acc90..ff01016efa 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -462,33 +462,31 @@ def test_show_and_verify_system_lags_output_lc4(self): assert return_code == 0 assert result == show_chassis_system_lags_output_lc4 - @mock.patch("sonic_py_common.device_info.is_smartswitch", return_value=True) - @mock.patch("config.chassis_modules.get_config_module_state", return_value='up') - def test_shutdown_triggers_transition_tracking(self, mock_state, mock_smartswitch): - db = FakeDb() - runner = CliRunner() + def test_shutdown_triggers_transition_tracking(self): + with mock.patch("sonic_py_common.device_info.is_smartswitch", return_value=True), \ + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up' - }) + db = FakeDb() + runner = CliRunner() - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up' + }) - print("Ram CLI Output:", result.output) - assert result.exit_code == 0 + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) - assert result.exit_code == 0, f"CLI failed: {result.output}" + print("CLI Output:", result.output) + fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") + print("fvs:", fvs) - # Verify CONFIG_DB is correctly updated - fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") - print("Ram fvs:{}".format(fvs)) - assert fvs.get("admin_status") == "down" - assert fvs.get("state_transition_in_progress") == "True" - assert "transition_start_time" in fvs + assert result.exit_code == 0 + assert fvs.get("admin_status") == "down" + assert fvs.get("state_transition_in_progress") == "True" + assert "transition_start_time" in fvs @classmethod def teardown_class(cls): From c980649695efdec5793a5f51e5afd46d80f91e2c Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 08:05:04 -0700 Subject: [PATCH 29/61] Adding coverage --- tests/chassis_modules_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index ff01016efa..4aaf592718 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -464,7 +464,7 @@ def test_show_and_verify_system_lags_output_lc4(self): def test_shutdown_triggers_transition_tracking(self): with mock.patch("sonic_py_common.device_info.is_smartswitch", return_value=True), \ - mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): db = FakeDb() runner = CliRunner() From a92d5e3fea5834f14d74bc194c9aaec030460b26 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 08:52:27 -0700 Subject: [PATCH 30/61] Adding debug log --- config/chassis_modules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/chassis_modules.py b/config/chassis_modules.py index b8c2fca90b..8063a9b2a0 100755 --- a/config/chassis_modules.py +++ b/config/chassis_modules.py @@ -164,7 +164,7 @@ def shutdown_chassis_module(db, chassis_module_name): click.echo(f"Module {chassis_module_name} state transition is already in progress") return - click.echo(f"Shutting down chassis module {chassis_module_name}") + click.echo(f"Smartswitch: Shutting down chassis module {chassis_module_name}") fvs = { 'admin_status': 'down', 'state_transition_in_progress': 'True', @@ -172,7 +172,7 @@ def shutdown_chassis_module(db, chassis_module_name): } config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs) else: - click.echo(f"Shutting down chassis module {chassis_module_name}") + click.echo(f"Non-Smartswitch: Shutting down chassis module {chassis_module_name}") config_db.set_entry('CHASSIS_MODULE', chassis_module_name, {'admin_status': 'down'}) if chassis_module_name.startswith("FABRIC-CARD"): From fb6b52bfeee3f169a2687eae50e6e1a07e562831 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 09:08:11 -0700 Subject: [PATCH 31/61] Adding debug to test --- tests/chassis_modules_test.py | 68 ++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 4aaf592718..1d06738641 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -463,6 +463,66 @@ def test_show_and_verify_system_lags_output_lc4(self): assert result == show_chassis_system_lags_output_lc4 def test_shutdown_triggers_transition_tracking(self): + with mock.patch("utilities_common.chassis.is_smartswitch", return_value=True), \ + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + + db = FakeDb() + runner = CliRunner() + + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up' + }) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + + print("1: CLI Output:", result.output) + fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") + print("1: fvs:", fvs) + + with mock.patch("utilities_common.chassis.is_smartswitch", return_value=True): + with mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + + db = FakeDb() + runner = CliRunner() + + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up' + }) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + + print("2: CLI Output:", result.output) + fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") + print("2: fvs:", fvs) + + with mock.patch("sonic_py_common.device_info.is_smartswitch", return_value=True): + with mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + + db = FakeDb() + runner = CliRunner() + + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up' + }) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + + print("3: CLI Output:", result.output) + fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") + print("3: fvs:", fvs) + with mock.patch("sonic_py_common.device_info.is_smartswitch", return_value=True), \ mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): @@ -483,10 +543,10 @@ def test_shutdown_triggers_transition_tracking(self): fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") print("fvs:", fvs) - assert result.exit_code == 0 - assert fvs.get("admin_status") == "down" - assert fvs.get("state_transition_in_progress") == "True" - assert "transition_start_time" in fvs + # assert result.exit_code == 0 + # assert fvs.get("admin_status") == "down" + # assert fvs.get("state_transition_in_progress") == "True" + # assert "transition_start_time" in fvs @classmethod def teardown_class(cls): From 5651ba866debd3fefef553a0075ec30a59782274 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 09:10:56 -0700 Subject: [PATCH 32/61] Adding debug to test --- tests/chassis_modules_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 1d06738641..df6c666265 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -543,10 +543,10 @@ def test_shutdown_triggers_transition_tracking(self): fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") print("fvs:", fvs) - # assert result.exit_code == 0 - # assert fvs.get("admin_status") == "down" - # assert fvs.get("state_transition_in_progress") == "True" - # assert "transition_start_time" in fvs + assert result.exit_code == 0 + assert fvs.get("admin_status") == "down" + assert fvs.get("state_transition_in_progress") == "True" + assert "transition_start_time" in fvs @classmethod def teardown_class(cls): From fe3eedf8be5dbfd5693f251bf3db3910b84504c1 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 10:29:42 -0700 Subject: [PATCH 33/61] Adding debug to test --- tests/chassis_modules_test.py | 76 ++++++----------------------------- 1 file changed, 12 insertions(+), 64 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index df6c666265..2adf01f4fd 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -142,10 +142,18 @@ def __init__(self): self.tables = {} def set_entry(self, table, key, value): - self.tables.setdefault(table, {})[key] = value + print(f"DEBUG: set_entry(table={table}, key={key}, value={value})") + + self.tables.setdefault(table, {}) + # Ensure existing entry is preserved and merged + if key not in self.tables[table]: + self.tables[table][key] = {} + self.tables[table][key].update(value) def get_entry(self, table, key): - return self.tables.get(table, {}).get(key, {}) + value = self.tables.get(table, {}).get(key, {}) + print(f"DEBUG: get_entry(table={table}, key={key}) => {value}") + return value def get_table(self, table): return self.tables.get(table, {}) @@ -463,67 +471,7 @@ def test_show_and_verify_system_lags_output_lc4(self): assert result == show_chassis_system_lags_output_lc4 def test_shutdown_triggers_transition_tracking(self): - with mock.patch("utilities_common.chassis.is_smartswitch", return_value=True), \ - mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - - db = FakeDb() - runner = CliRunner() - - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up' - }) - - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - - print("1: CLI Output:", result.output) - fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") - print("1: fvs:", fvs) - - with mock.patch("utilities_common.chassis.is_smartswitch", return_value=True): - with mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - - db = FakeDb() - runner = CliRunner() - - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up' - }) - - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - - print("2: CLI Output:", result.output) - fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") - print("2: fvs:", fvs) - - with mock.patch("sonic_py_common.device_info.is_smartswitch", return_value=True): - with mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - - db = FakeDb() - runner = CliRunner() - - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up' - }) - - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - - print("3: CLI Output:", result.output) - fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") - print("3: fvs:", fvs) - - with mock.patch("sonic_py_common.device_info.is_smartswitch", return_value=True), \ + with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): db = FakeDb() @@ -541,7 +489,7 @@ def test_shutdown_triggers_transition_tracking(self): print("CLI Output:", result.output) fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") - print("fvs:", fvs) + print("Final FVS:", fvs) assert result.exit_code == 0 assert fvs.get("admin_status") == "down" From cb0e5d4607dfc45b4bdd7c9b69228886ae1abe72 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 11:10:56 -0700 Subject: [PATCH 34/61] Adding debug to test --- tests/chassis_modules_test.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 2adf01f4fd..fcf419cfb5 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -139,24 +139,28 @@ def mock_run_command_side_effect(*args, **kwargs): class FakeConfigDBConnector: def __init__(self): - self.tables = {} + self.data = {} def set_entry(self, table, key, value): - print(f"DEBUG: set_entry(table={table}, key={key}, value={value})") - - self.tables.setdefault(table, {}) - # Ensure existing entry is preserved and merged - if key not in self.tables[table]: - self.tables[table][key] = {} - self.tables[table][key].update(value) + full_key = f"{table}|{key}" + print(f"[SET] {full_key} = {value}") + existing = self.data.get(full_key, {}) + existing.update(value) + self.data[full_key] = existing def get_entry(self, table, key): - value = self.tables.get(table, {}).get(key, {}) - print(f"DEBUG: get_entry(table={table}, key={key}) => {value}") + full_key = f"{table}|{key}" + value = self.data.get(full_key, {}) + print(f"[GET] {full_key} => {value}") return value def get_table(self, table): - return self.tables.get(table, {}) + result = {} + for full_key, val in self.data.items(): + if full_key.startswith(f"{table}|"): + _, key = full_key.split('|', 1) + result[key] = val + return result class FakeDb: From b7ee989fe2d30f3431922a48fb8d8253ec2d1403 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 11:48:00 -0700 Subject: [PATCH 35/61] Adding debug to test --- tests/chassis_modules_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index fcf419cfb5..7de6dd35ea 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -482,7 +482,8 @@ def test_shutdown_triggers_transition_tracking(self): runner = CliRunner() db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up' + 'admin_status': 'up', + 'state_transition_in_progress': 'False' }) result = runner.invoke( From c3cbebef76b3d0ceed03b78f6640dd8a4dd6ef02 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 12:55:53 -0700 Subject: [PATCH 36/61] Adding debug to test --- config/chassis_modules.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/config/chassis_modules.py b/config/chassis_modules.py index 8063a9b2a0..fc8f23ba15 100755 --- a/config/chassis_modules.py +++ b/config/chassis_modules.py @@ -38,9 +38,10 @@ def get_config_module_state(db, chassis_module_name): def get_state_transition_in_progress(db, chassis_module_name): - config_db = db.cfgdb - fvs = config_db.get_entry('CHASSIS_MODULE', chassis_module_name) - return fvs.get('state_transition_in_progress', 'False') if fvs else 'False' + fvs = db.cfgdb.get_entry('CHASSIS_MODULE', chassis_module_name) + value = fvs.get('state_transition_in_progress', 'False') if fvs else 'False' + print(f"[STATE CHECK] state_transition_in_progress = {value}") + return value def set_state_transition_in_progress(db, chassis_module_name, value): @@ -157,10 +158,13 @@ def shutdown_chassis_module(db, chassis_module_name): if is_smartswitch(): if get_state_transition_in_progress(db, chassis_module_name) == 'True': + click.echo("DEBUG: Transition in progress is TRUE") if is_transition_timed_out(db, chassis_module_name): + click.echo("DEBUG: Transition timed out — continuing shutdown") set_state_transition_in_progress(db, chassis_module_name, 'False') click.echo(f"Previous transition for module {chassis_module_name} timed out. Proceeding with shutdown.") else: + click.echo("DEBUG: Transition not timed out — exiting") click.echo(f"Module {chassis_module_name} state transition is already in progress") return From 36f8216b3419478a91644e01e17bbfc3e94cd9d4 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 13:54:47 -0700 Subject: [PATCH 37/61] Adding debug to test --- config/chassis_modules.py | 1 + tests/chassis_modules_test.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/config/chassis_modules.py b/config/chassis_modules.py index fc8f23ba15..f57108f788 100755 --- a/config/chassis_modules.py +++ b/config/chassis_modules.py @@ -169,6 +169,7 @@ def shutdown_chassis_module(db, chassis_module_name): return click.echo(f"Smartswitch: Shutting down chassis module {chassis_module_name}") + click.echo(f"DEBUG: Using cfgdb ID: {id(config_db)}") fvs = { 'admin_status': 'down', 'state_transition_in_progress': 'True', diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 7de6dd35ea..ab815384ae 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -142,6 +142,7 @@ def __init__(self): self.data = {} def set_entry(self, table, key, value): + print(f"[SET] called on id={id(self)}: {table}|{key} = {value}") full_key = f"{table}|{key}" print(f"[SET] {full_key} = {value}") existing = self.data.get(full_key, {}) @@ -501,6 +502,33 @@ def test_shutdown_triggers_transition_tracking(self): assert fvs.get("state_transition_in_progress") == "True" assert "transition_start_time" in fvs + @mock.patch("config.chassis_modules.ConfigDBConnector", return_value=FakeConfigDBConnector()) + @mock.patch("config.chassis_modules.is_smartswitch", return_value=True) + @mock.patch("config.chassis_modules.get_config_module_state", return_value='up') + def test_shutdown_triggers_transition_tracking_test(self, mock_state, mock_smartswitch, mock_cfg): + db = FakeDb() + runner = CliRunner() + + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up', + 'state_transition_in_progress': 'False' + }) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + + print("CLI Output:", result.output) + fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") + print("Final FVS:", fvs) + + assert result.exit_code == 0 + assert fvs.get("admin_status") == "down" + assert fvs.get("state_transition_in_progress") == "True" + assert "transition_start_time" in fvs + @classmethod def teardown_class(cls): print("TEARDOWN") From 05d1d86164937afc7f639233e8ac0aa2e9933fab Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 14:53:01 -0700 Subject: [PATCH 38/61] Adding debug to test --- tests/chassis_modules_test.py | 67 +++++++++-------------------------- 1 file changed, 17 insertions(+), 50 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index ab815384ae..7fcec211db 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -139,20 +139,15 @@ def mock_run_command_side_effect(*args, **kwargs): class FakeConfigDBConnector: def __init__(self): - self.data = {} + self.tables = {} def set_entry(self, table, key, value): - print(f"[SET] called on id={id(self)}: {table}|{key} = {value}") - full_key = f"{table}|{key}" - print(f"[SET] {full_key} = {value}") - existing = self.data.get(full_key, {}) - existing.update(value) - self.data[full_key] = existing + print(f"[SET] {table}|{key} = {value}") + self.tables.setdefault(table, {}).setdefault(key, {}).update(value) def get_entry(self, table, key): - full_key = f"{table}|{key}" - value = self.data.get(full_key, {}) - print(f"[GET] {full_key} => {value}") + value = self.tables.get(table, {}).get(key, {}) + print(f"[GET] {table}|{key} => {value}") return value def get_table(self, table): @@ -164,11 +159,6 @@ def get_table(self, table): return result -class FakeDb: - def __init__(self): - self.cfgdb = FakeConfigDBConnector() - - class TestChassisModules(object): @classmethod def setup_class(cls): @@ -475,44 +465,21 @@ def test_show_and_verify_system_lags_output_lc4(self): assert return_code == 0 assert result == show_chassis_system_lags_output_lc4 - def test_shutdown_triggers_transition_tracking(self): - with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ - mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - - db = FakeDb() - runner = CliRunner() - - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up', - 'state_transition_in_progress': 'False' - }) - - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - - print("CLI Output:", result.output) - fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") - print("Final FVS:", fvs) + @mock.patch("config.chassis_modules.is_smartswitch", return_value=True) + @mock.patch("config.chassis_modules.get_config_module_state", return_value="up") + def test_shutdown_triggers_transition_tracking(mock_get_state, mock_is_smartswitch): + fake_cfgdb = FakeConfigDBConnector() + fake_cfgdb.set_entry("CHASSIS_MODULE", "DPU0", { + "admin_status": "up", + "state_transition_in_progress": "False" + }) - assert result.exit_code == 0 - assert fvs.get("admin_status") == "down" - assert fvs.get("state_transition_in_progress") == "True" - assert "transition_start_time" in fvs + class FakeDb: + def __init__(self): + self.cfgdb = fake_cfgdb - @mock.patch("config.chassis_modules.ConfigDBConnector", return_value=FakeConfigDBConnector()) - @mock.patch("config.chassis_modules.is_smartswitch", return_value=True) - @mock.patch("config.chassis_modules.get_config_module_state", return_value='up') - def test_shutdown_triggers_transition_tracking_test(self, mock_state, mock_smartswitch, mock_cfg): - db = FakeDb() runner = CliRunner() - - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up', - 'state_transition_in_progress': 'False' - }) + db = FakeDb() result = runner.invoke( config.config.commands["chassis"].commands["modules"].commands["shutdown"], From 788137ce7c0dbbba130bb0321a4779b348567926 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 15:48:25 -0700 Subject: [PATCH 39/61] Adding debug to test --- tests/chassis_modules_test.py | 49 ++++++++++++++++------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 7fcec211db..6707c5ecaa 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -465,36 +465,33 @@ def test_show_and_verify_system_lags_output_lc4(self): assert return_code == 0 assert result == show_chassis_system_lags_output_lc4 - @mock.patch("config.chassis_modules.is_smartswitch", return_value=True) - @mock.patch("config.chassis_modules.get_config_module_state", return_value="up") - def test_shutdown_triggers_transition_tracking(mock_get_state, mock_is_smartswitch): - fake_cfgdb = FakeConfigDBConnector() - fake_cfgdb.set_entry("CHASSIS_MODULE", "DPU0", { - "admin_status": "up", - "state_transition_in_progress": "False" - }) - - class FakeDb: - def __init__(self): - self.cfgdb = fake_cfgdb + def test_shutdown_triggers_transition_tracking(self): + with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - runner = CliRunner() - db = FakeDb() + db = FakeDb() + runner = CliRunner() - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) + # Prepopulate entry to simulate a valid 'up' state and no transition yet + db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { + 'admin_status': 'up', + 'state_transition_in_progress': 'False' + }) - print("CLI Output:", result.output) - fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") - print("Final FVS:", fvs) + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) - assert result.exit_code == 0 - assert fvs.get("admin_status") == "down" - assert fvs.get("state_transition_in_progress") == "True" - assert "transition_start_time" in fvs + print("CLI Output:", result.output) + fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") + print("Final FVS:", fvs) + + assert result.exit_code == 0 + assert fvs.get("admin_status") == "down" + assert fvs.get("state_transition_in_progress") == "True" + assert "transition_start_time" in fvs @classmethod def teardown_class(cls): From 3b6410beafd29c43172bcfea0c3b09bbab0cef64 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 16:06:48 -0700 Subject: [PATCH 40/61] Adding debug to test --- tests/chassis_modules_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 6707c5ecaa..b5415093d4 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -469,7 +469,7 @@ def test_shutdown_triggers_transition_tracking(self): with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - db = FakeDb() + db = FakeConfigDBConnector() runner = CliRunner() # Prepopulate entry to simulate a valid 'up' state and no transition yet From 49962927a7e59f4d67fdfdc44b19f0472e063b8d Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 16:17:11 -0700 Subject: [PATCH 41/61] Adding debug to test --- tests/chassis_modules_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index b5415093d4..7685480936 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -467,7 +467,7 @@ def test_show_and_verify_system_lags_output_lc4(self): def test_shutdown_triggers_transition_tracking(self): with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ - mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): db = FakeConfigDBConnector() runner = CliRunner() From 82cd1454d9488d4112d71b71a00382f29723cb6e Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 17:03:16 -0700 Subject: [PATCH 42/61] Adding debug to test --- tests/chassis_modules_test.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 7685480936..93ed5340a1 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -469,15 +469,19 @@ def test_shutdown_triggers_transition_tracking(self): with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - db = FakeConfigDBConnector() - runner = CliRunner() - - # Prepopulate entry to simulate a valid 'up' state and no transition yet - db.cfgdb.set_entry('CHASSIS_MODULE', 'DPU0', { - 'admin_status': 'up', - 'state_transition_in_progress': 'False' + fake_cfgdb = FakeConfigDBConnector() + fake_cfgdb.set_entry("CHASSIS_MODULE", "DPU0", { + "admin_status": "up", + "state_transition_in_progress": "False" }) + class FakeDb: + def __init__(self): + self.cfgdb = fake_cfgdb + + runner = CliRunner() + db = FakeDb() + result = runner.invoke( config.config.commands["chassis"].commands["modules"].commands["shutdown"], ["DPU0"], From e6a2de52a990eb8416632a5360a60504173c1332 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 17:47:00 -0700 Subject: [PATCH 43/61] Adding debug to test --- tests/chassis_modules_test.py | 62 +++++++++-------------------------- 1 file changed, 15 insertions(+), 47 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 93ed5340a1..ccd552c514 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -137,28 +137,6 @@ def mock_run_command_side_effect(*args, **kwargs): return '', 0 -class FakeConfigDBConnector: - def __init__(self): - self.tables = {} - - def set_entry(self, table, key, value): - print(f"[SET] {table}|{key} = {value}") - self.tables.setdefault(table, {}).setdefault(key, {}).update(value) - - def get_entry(self, table, key): - value = self.tables.get(table, {}).get(key, {}) - print(f"[GET] {table}|{key} => {value}") - return value - - def get_table(self, table): - result = {} - for full_key, val in self.data.items(): - if full_key.startswith(f"{table}|"): - _, key = full_key.split('|', 1) - result[key] = val - return result - - class TestChassisModules(object): @classmethod def setup_class(cls): @@ -469,33 +447,23 @@ def test_shutdown_triggers_transition_tracking(self): with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): - fake_cfgdb = FakeConfigDBConnector() - fake_cfgdb.set_entry("CHASSIS_MODULE", "DPU0", { - "admin_status": "up", - "state_transition_in_progress": "False" - }) - - class FakeDb: - def __init__(self): - self.cfgdb = fake_cfgdb - runner = CliRunner() - db = FakeDb() - - result = runner.invoke( - config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], - obj=db - ) - - print("CLI Output:", result.output) - fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") - print("Final FVS:", fvs) - + db = Db() + result = runner.invoke(config.config.commands["chassis"].commands["modules"].commands["shutdown"], ["DPU0"], obj=db) + print(result.exit_code) + print(result.output) assert result.exit_code == 0 - assert fvs.get("admin_status") == "down" - assert fvs.get("state_transition_in_progress") == "True" - assert "transition_start_time" in fvs + + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], ["DPU0"], obj=db) + print(result.exit_code) + print(result.output) + result_lines = result.output.strip('\n').split('\n') + print(result_lines) + # assert result.exit_code == 0 + # header_lines = 2 + result_out = " ".join((result_lines[header_lines]).split()) + print(result_out) + # assert result_out.strip('\n') == show_linecard0_shutdown_output.strip('\n') @classmethod def teardown_class(cls): From d86eb5bf2dcda421ac5eb0e8846c0adca65cee1b Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 17:50:27 -0700 Subject: [PATCH 44/61] Adding debug to test --- tests/chassis_modules_test.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index ccd552c514..19ac4e7621 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -449,12 +449,20 @@ def test_shutdown_triggers_transition_tracking(self): runner = CliRunner() db = Db() - result = runner.invoke(config.config.commands["chassis"].commands["modules"].commands["shutdown"], ["DPU0"], obj=db) + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) print(result.exit_code) print(result.output) assert result.exit_code == 0 - result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], ["DPU0"], obj=db) + result = runner.invoke( + show.cli.commands["chassis"].commands["modules"].commands["status"], + ["DPU0"], + obj=db + ) print(result.exit_code) print(result.output) result_lines = result.output.strip('\n').split('\n') From 51ccd66945a8ffc8638993d239c88e29b29ac0f2 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 17:54:14 -0700 Subject: [PATCH 45/61] Adding debug to test --- tests/chassis_modules_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 19ac4e7621..ae64ac7793 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -451,7 +451,7 @@ def test_shutdown_triggers_transition_tracking(self): db = Db() result = runner.invoke( config.config.commands["chassis"].commands["modules"].commands["shutdown"], - ["DPU0"], + ["DPU0"], obj=db ) print(result.exit_code) From e749259ee41f8f49d54389501af97a075a0db653 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 18:44:42 -0700 Subject: [PATCH 46/61] Adding debug to test --- tests/chassis_modules_test.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index ae64ac7793..9dc4484360 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -458,20 +458,14 @@ def test_shutdown_triggers_transition_tracking(self): print(result.output) assert result.exit_code == 0 - result = runner.invoke( - show.cli.commands["chassis"].commands["modules"].commands["status"], - ["DPU0"], - obj=db - ) - print(result.exit_code) - print(result.output) - result_lines = result.output.strip('\n').split('\n') - print(result_lines) + fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + print(f"admin_status:{fvs['admin_status']}") + print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") + print(f"transition_start_time:{fvs['transition_start_time']}") + # assert fvs['admin_status'] == 'down' + # assert fvs['state_transition_in_progress'] == 'True' + # assert 'transition_start_time' in fvs # assert result.exit_code == 0 - # header_lines = 2 - result_out = " ".join((result_lines[header_lines]).split()) - print(result_out) - # assert result_out.strip('\n') == show_linecard0_shutdown_output.strip('\n') @classmethod def teardown_class(cls): From b0a1fde3892d6d77eb2787ac6fcc7b5a3f174561 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 19:21:20 -0700 Subject: [PATCH 47/61] Adding debug to test --- tests/chassis_modules_test.py | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 9dc4484360..32b63495aa 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -462,9 +462,35 @@ def test_shutdown_triggers_transition_tracking(self): print(f"admin_status:{fvs['admin_status']}") print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") - # assert fvs['admin_status'] == 'down' - # assert fvs['state_transition_in_progress'] == 'True' - # assert 'transition_start_time' in fvs + # assert result.exit_code == 0 + + def test_shutdown_triggers_transition_in_progress(self): + with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + + runner = CliRunner() + db = Db() + + fvs = { + 'admin_status': 'up', + 'state_transition_in_progress': 'True', + 'transition_start_time': datetime.utcnow().isoformat() + } + db.cfgdb.set_entry('CHASSIS_MODULE', chassis_module_name, fvs) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + print(f"admin_status:{fvs['admin_status']}") + print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") + print(f"transition_start_time:{fvs['transition_start_time']}") # assert result.exit_code == 0 @classmethod From d100fae95ec9e6a404616f9190196d665db5b20c Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 19:42:48 -0700 Subject: [PATCH 48/61] Adding debug to test --- tests/chassis_modules_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 32b63495aa..ed71e558cf 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -1,6 +1,7 @@ import sys import os from click.testing import CliRunner +from datetime import datetime # from datetime import datetime, timedelta # from config.chassis_modules import TRANSITION_TIMEOUT @@ -476,7 +477,7 @@ def test_shutdown_triggers_transition_in_progress(self): 'state_transition_in_progress': 'True', 'transition_start_time': datetime.utcnow().isoformat() } - db.cfgdb.set_entry('CHASSIS_MODULE', chassis_module_name, fvs) + db.cfgdb.set_entry('CHASSIS_MODULE', "DPU0" fvs) result = runner.invoke( config.config.commands["chassis"].commands["modules"].commands["shutdown"], From e908c12eafe8de7a7463dee1561693ddd1733ea1 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 19:53:31 -0700 Subject: [PATCH 49/61] Adding debug to test --- tests/chassis_modules_test.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index ed71e558cf..3f8d1c3232 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -477,7 +477,35 @@ def test_shutdown_triggers_transition_in_progress(self): 'state_transition_in_progress': 'True', 'transition_start_time': datetime.utcnow().isoformat() } - db.cfgdb.set_entry('CHASSIS_MODULE', "DPU0" fvs) + db.cfgdb.set_entry('CHASSIS_MODULE', "DPU0, fvs) + + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["shutdown"], + ["DPU0"], + obj=db + ) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + print(f"admin_status:{fvs['admin_status']}") + print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") + print(f"transition_start_time:{fvs['transition_start_time']}") + + def test_shutdown_triggers_transition_timeout(self): + with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ + mock.patch("config.chassis_modules.get_config_module_state", return_value='up'): + + runner = CliRunner() + db = Db() + + fvs = { + 'admin_status': 'up', + 'state_transition_in_progress': 'True', + 'transition_start_time': (datetime.datetime.utcnow() - datetime.timedelta(minutes=30)).isoformat() + } + db.cfgdb.set_entry('CHASSIS_MODULE', "DPU0", fvs) result = runner.invoke( config.config.commands["chassis"].commands["modules"].commands["shutdown"], @@ -492,7 +520,6 @@ def test_shutdown_triggers_transition_in_progress(self): print(f"admin_status:{fvs['admin_status']}") print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") - # assert result.exit_code == 0 @classmethod def teardown_class(cls): From 1dbe13624b86433f93eb07765a7a8bbb10799e9a Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 19:57:45 -0700 Subject: [PATCH 50/61] Adding debug to test --- tests/chassis_modules_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 3f8d1c3232..09a3904a34 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -477,7 +477,7 @@ def test_shutdown_triggers_transition_in_progress(self): 'state_transition_in_progress': 'True', 'transition_start_time': datetime.utcnow().isoformat() } - db.cfgdb.set_entry('CHASSIS_MODULE', "DPU0, fvs) + db.cfgdb.set_entry('CHASSIS_MODULE', "DPU0", fvs) result = runner.invoke( config.config.commands["chassis"].commands["modules"].commands["shutdown"], From b7a31babe53350637b7a980e53feddb589a8dac7 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 15 Apr 2025 20:26:56 -0700 Subject: [PATCH 51/61] Adding debug to test --- tests/chassis_modules_test.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 09a3904a34..22c0f7ebc2 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -503,7 +503,7 @@ def test_shutdown_triggers_transition_timeout(self): fvs = { 'admin_status': 'up', 'state_transition_in_progress': 'True', - 'transition_start_time': (datetime.datetime.utcnow() - datetime.timedelta(minutes=30)).isoformat() + 'transition_start_time': (datetime.utcnow() - datetime.timedelta(minutes=30)).isoformat() } db.cfgdb.set_entry('CHASSIS_MODULE', "DPU0", fvs) @@ -521,6 +521,26 @@ def test_shutdown_triggers_transition_timeout(self): print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") + def test_startup_triggers_transition_tracking(self): + with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ + mock.patch("config.chassis_modules.get_config_module_state", return_value='down'): + + runner = CliRunner() + db = Db() + result = runner.invoke( + config.config.commands["chassis"].commands["modules"].commands["startup"], + ["DPU0"], + obj=db + ) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + + fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + print(f"admin_status:{fvs['admin_status']}") + print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") + print(f"transition_start_time:{fvs['transition_start_time']}") + @classmethod def teardown_class(cls): print("TEARDOWN") From 0fd638d21df35c6a5393fc438eaf6debeff24293 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Fri, 18 Apr 2025 17:23:57 -0700 Subject: [PATCH 52/61] fixing overage --- tests/chassis_modules_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 22c0f7ebc2..21a257d307 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -1,8 +1,7 @@ import sys import os from click.testing import CliRunner -from datetime import datetime -# from datetime import datetime, timedelta +from datetime import datetime, timedelta # from config.chassis_modules import TRANSITION_TIMEOUT import show.main as show @@ -503,7 +502,7 @@ def test_shutdown_triggers_transition_timeout(self): fvs = { 'admin_status': 'up', 'state_transition_in_progress': 'True', - 'transition_start_time': (datetime.utcnow() - datetime.timedelta(minutes=30)).isoformat() + 'transition_start_time': (datetime.utcnow() - timedelta(minutes=30)).isoformat() } db.cfgdb.set_entry('CHASSIS_MODULE', "DPU0", fvs) From 916c5854d1993b8914062dcad69127c7d84a6942 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Tue, 29 Apr 2025 15:01:03 -0700 Subject: [PATCH 53/61] Addressed a review comments --- config/chassis_modules.py | 58 +++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/config/chassis_modules.py b/config/chassis_modules.py index f57108f788..c4d8b4db67 100755 --- a/config/chassis_modules.py +++ b/config/chassis_modules.py @@ -11,6 +11,21 @@ TIMEOUT_SECS = 10 TRANSITION_TIMEOUT = timedelta(seconds=240) # 4 minutes +class StateDBHelper: + def __init__(self, sonic_db): + self.db = sonic_db + + def get_entry(self, table, key): + """Fetch all fields from table|key.""" + redis_key = f"{table}|{key}" + return self.db.get_all("STATE_DB", redis_key) or {} + + def set_entry(self, table, key, entry): + """Set multiple fields to table|key.""" + redis_key = f"{table}|{key}" + for field, value in entry.items(): + self.db.set("STATE_DB", redis_key, field, value) + # # 'chassis_modules' group ('config chassis_modules ...') # @@ -24,6 +39,11 @@ def modules(): """Configure chassis modules""" pass +def ensure_statedb_connected(db): + if not hasattr(db, 'statedb'): + chassisdb = db.db + chassisdb.connect("STATE_DB") + db.statedb = StateDBHelper(chassisdb) def get_config_module_state(db, chassis_module_name): config_db = db.cfgdb @@ -36,28 +56,29 @@ def get_config_module_state(db, chassis_module_name): else: return fvs['admin_status'] - def get_state_transition_in_progress(db, chassis_module_name): - fvs = db.cfgdb.get_entry('CHASSIS_MODULE', chassis_module_name) + ensure_statedb_connected(db) + fvs = db.statedb.get_entry('CHASSIS_MODULE_TABLE', chassis_module_name) value = fvs.get('state_transition_in_progress', 'False') if fvs else 'False' - print(f"[STATE CHECK] state_transition_in_progress = {value}") return value def set_state_transition_in_progress(db, chassis_module_name, value): - config_db = db.cfgdb - entry = config_db.get_entry('CHASSIS_MODULE', chassis_module_name) or {} + ensure_statedb_connected(db) + state_db = db.statedb + entry = state_db.get_entry('CHASSIS_MODULE_TABLE', chassis_module_name) or {} entry['state_transition_in_progress'] = value if value == 'True': entry['transition_start_time'] = datetime.utcnow().isoformat() else: entry.pop('transition_start_time', None) - config_db.set_entry('CHASSIS_MODULE', chassis_module_name, entry) + state_db.set_entry('CHASSIS_MODULE_TABLE', chassis_module_name, entry) def is_transition_timed_out(db, chassis_module_name): - config_db = db.cfgdb - fvs = config_db.get_entry('CHASSIS_MODULE', chassis_module_name) + ensure_statedb_connected(db) + state_db = db.statedb + fvs = state_db.get_entry('CHASSIS_MODULE_TABLE', chassis_module_name) if not fvs: return False start_time_str = fvs.get('transition_start_time') @@ -151,6 +172,7 @@ def shutdown_chassis_module(db, chassis_module_name): if not chassis_module_name.startswith(("SUPERVISOR", "LINE-CARD", "FABRIC-CARD", "DPU")): ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD', 'FABRIC-CARD', or 'DPU'") + return if get_config_module_state(db, chassis_module_name) == 'down': click.echo(f"Module {chassis_module_name} is already in down state") @@ -158,26 +180,22 @@ def shutdown_chassis_module(db, chassis_module_name): if is_smartswitch(): if get_state_transition_in_progress(db, chassis_module_name) == 'True': - click.echo("DEBUG: Transition in progress is TRUE") if is_transition_timed_out(db, chassis_module_name): - click.echo("DEBUG: Transition timed out — continuing shutdown") set_state_transition_in_progress(db, chassis_module_name, 'False') click.echo(f"Previous transition for module {chassis_module_name} timed out. Proceeding with shutdown.") else: - click.echo("DEBUG: Transition not timed out — exiting") click.echo(f"Module {chassis_module_name} state transition is already in progress") return + else: + set_state_transition_in_progress(db, chassis_module_name, 'True') - click.echo(f"Smartswitch: Shutting down chassis module {chassis_module_name}") - click.echo(f"DEBUG: Using cfgdb ID: {id(config_db)}") + click.echo(f"Shutting down chassis module {chassis_module_name}") fvs = { 'admin_status': 'down', - 'state_transition_in_progress': 'True', - 'transition_start_time': datetime.utcnow().isoformat() } config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs) else: - click.echo(f"Non-Smartswitch: Shutting down chassis module {chassis_module_name}") + click.echo(f"Shutting down chassis module {chassis_module_name}") config_db.set_entry('CHASSIS_MODULE', chassis_module_name, {'admin_status': 'down'}) if chassis_module_name.startswith("FABRIC-CARD"): @@ -199,6 +217,10 @@ def startup_chassis_module(db, chassis_module_name): config_db = db.cfgdb ctx = click.get_current_context() + if not chassis_module_name.startswith(("SUPERVISOR", "LINE-CARD", "FABRIC-CARD", "DPU")): + ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD', 'FABRIC-CARD', or 'DPU'") + return + if get_config_module_state(db, chassis_module_name) == 'up': click.echo(f"Module {chassis_module_name} is already set to up state") return @@ -211,12 +233,12 @@ def startup_chassis_module(db, chassis_module_name): else: click.echo(f"Module {chassis_module_name} state transition is already in progress") return + else: + set_state_transition_in_progress(db, chassis_module_name, 'True') click.echo(f"Starting up chassis module {chassis_module_name}") fvs = { 'admin_status': 'up', - 'state_transition_in_progress': 'True', - 'transition_start_time': datetime.utcnow().isoformat() } config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs) else: From 579a55fac73a39cff3cb7d0894bc35109b6c5a9b Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Wed, 30 Apr 2025 10:09:07 -0700 Subject: [PATCH 54/61] Fixed SA issues --- config/chassis_modules.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/chassis_modules.py b/config/chassis_modules.py index c4d8b4db67..880022d90c 100755 --- a/config/chassis_modules.py +++ b/config/chassis_modules.py @@ -11,6 +11,7 @@ TIMEOUT_SECS = 10 TRANSITION_TIMEOUT = timedelta(seconds=240) # 4 minutes + class StateDBHelper: def __init__(self, sonic_db): self.db = sonic_db @@ -39,6 +40,7 @@ def modules(): """Configure chassis modules""" pass + def ensure_statedb_connected(db): if not hasattr(db, 'statedb'): chassisdb = db.db @@ -56,6 +58,7 @@ def get_config_module_state(db, chassis_module_name): else: return fvs['admin_status'] + def get_state_transition_in_progress(db, chassis_module_name): ensure_statedb_connected(db) fvs = db.statedb.get_entry('CHASSIS_MODULE_TABLE', chassis_module_name) From 0ba6b90fbadb7d93949b461d57e857b068024a4c Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Wed, 30 Apr 2025 11:02:53 -0700 Subject: [PATCH 55/61] Fixing UT --- tests/chassis_modules_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 21a257d307..d21898feaa 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -458,7 +458,7 @@ def test_shutdown_triggers_transition_tracking(self): print(result.output) assert result.exit_code == 0 - fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + fvs = db.db.get_all("STATE_DB", "CHASSIS_MODULE_TABLE|DPU0") print(f"admin_status:{fvs['admin_status']}") print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") @@ -487,7 +487,7 @@ def test_shutdown_triggers_transition_in_progress(self): print(result.output) assert result.exit_code == 0 - fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + fvs = db.db.get_all("STATE_DB", "CHASSIS_MODULE_TABLE|DPU0") print(f"admin_status:{fvs['admin_status']}") print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") @@ -515,7 +515,7 @@ def test_shutdown_triggers_transition_timeout(self): print(result.output) assert result.exit_code == 0 - fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + fvs = db.db.get_all("STATE_DB", "CHASSIS_MODULE_TABLE|DPU0") print(f"admin_status:{fvs['admin_status']}") print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") @@ -535,7 +535,7 @@ def test_startup_triggers_transition_tracking(self): print(result.output) assert result.exit_code == 0 - fvs = db.cfgdb.get_entry('CHASSIS_MODULE', 'DPU0') + fvs = db.db.get_all("STATE_DB", "CHASSIS_MODULE_TABLE|DPU0") print(f"admin_status:{fvs['admin_status']}") print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") From 250730f73ebdbe20189eee3c7a93c7c1a888df23 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Wed, 30 Apr 2025 12:09:15 -0700 Subject: [PATCH 56/61] Fixing UT --- tests/chassis_modules_test.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index d21898feaa..d574ca2404 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -458,11 +458,22 @@ def test_shutdown_triggers_transition_tracking(self): print(result.output) assert result.exit_code == 0 - fvs = db.db.get_all("STATE_DB", "CHASSIS_MODULE_TABLE|DPU0") - print(f"admin_status:{fvs['admin_status']}") - print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") - print(f"transition_start_time:{fvs['transition_start_time']}") - # assert result.exit_code == 0 + # Check CONFIG_DB for admin_status + cfg_fvs = db.cfgdb.get_entry("CHASSIS_MODULE", "DPU0") + admin_status = cfg_fvs.get("admin_status") + print(f"admin_status: {admin_status}") + assert admin_status == "down" + + # Check STATE_DB for transition flags + state_fvs = db.db.get_all("STATE_DB", "CHASSIS_MODULE_TABLE|DPU0") + transition_flag = state_fvs.get("state_transition_in_progress") + transition_time = state_fvs.get("transition_start_time") + + print(f"state_transition_in_progress: {transition_flag}") + print(f"transition_start_time: {transition_time}") + + assert transition_flag == "True" + assert transition_time is not None def test_shutdown_triggers_transition_in_progress(self): with mock.patch("config.chassis_modules.is_smartswitch", return_value=True), \ From a2a1cd53cf4f80c1b8a448f290f1a2712ec7877f Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Wed, 30 Apr 2025 19:50:21 -0700 Subject: [PATCH 57/61] Fixing UT issues --- tests/chassis_modules_test.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index d574ca2404..ab416c181d 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -499,7 +499,6 @@ def test_shutdown_triggers_transition_in_progress(self): assert result.exit_code == 0 fvs = db.db.get_all("STATE_DB", "CHASSIS_MODULE_TABLE|DPU0") - print(f"admin_status:{fvs['admin_status']}") print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") @@ -527,7 +526,6 @@ def test_shutdown_triggers_transition_timeout(self): assert result.exit_code == 0 fvs = db.db.get_all("STATE_DB", "CHASSIS_MODULE_TABLE|DPU0") - print(f"admin_status:{fvs['admin_status']}") print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") @@ -547,7 +545,6 @@ def test_startup_triggers_transition_tracking(self): assert result.exit_code == 0 fvs = db.db.get_all("STATE_DB", "CHASSIS_MODULE_TABLE|DPU0") - print(f"admin_status:{fvs['admin_status']}") print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") From 6988eda2dbb543170814fda95c0ce147c66d5091 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Wed, 30 Apr 2025 20:31:56 -0700 Subject: [PATCH 58/61] Improving coverage --- tests/chassis_modules_test.py | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index ab416c181d..f53dd7f5bf 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -548,6 +548,68 @@ def test_startup_triggers_transition_tracking(self): print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") + def test_set_state_transition_in_progress_sets_and_removes_timestamp(): + db = MagicMock() + db.statedb = MagicMock() + + # Case 1: Set value to 'True' (adds timestamp) + db.statedb.get_entry.return_value = {} + set_state_transition_in_progress(db, "DPU0", "True") + + args = db.statedb.set_entry.call_args[0] + assert args[0] == "CHASSIS_MODULE_TABLE" + assert args[1] == "DPU0" + updated_entry = args[2] + assert updated_entry['state_transition_in_progress'] == "True" + assert "transition_start_time" in updated_entry + + # Case 2: Set value to 'False' (removes timestamp) + db.statedb.get_entry.return_value = { + "state_transition_in_progress": "True", + "transition_start_time": "2025-05-01T01:00:00" + } + set_state_transition_in_progress(db, "DPU0", "False") + + args = db.statedb.set_entry.call_args[0] + updated_entry = args[2] + assert updated_entry['state_transition_in_progress'] == "False" + assert "transition_start_time" not in updated_entry + + def test_is_transition_timed_out_all_paths(): + db = MagicMock() + db.statedb = MagicMock() + + # Case 1: No entry + db.statedb.get_entry.return_value = None + assert is_transition_timed_out(db, "DPU0") is False + + # Case 2: No transition_start_time + db.statedb.get_entry.return_value = {"state_transition_in_progress": "True"} + assert is_transition_timed_out(db, "DPU0") is False + + # Case 3: Bad datetime format + db.statedb.get_entry.return_value = { + "state_transition_in_progress": "True", + "transition_start_time": "bad-format" + } + assert is_transition_timed_out(db, "DPU0") is False + + # Case 4: Timeout exceeded + past_time = (datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=1)).isoformat() + db.statedb.get_entry.return_value = { + "state_transition_in_progress": "True", + "transition_start_time": past_time + } + assert is_transition_timed_out(db, "DPU0") is True + + # Case 5: Not yet timed out + recent_time = datetime.utcnow().isoformat() + db.statedb.get_entry.return_value = { + "state_transition_in_progress": "True", + "transition_start_time": recent_time + } + assert is_transition_timed_out(db, "DPU0") is False + @classmethod def teardown_class(cls): print("TEARDOWN") From 27c0b10e3203415277812941fe9f51a29a3968d2 Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Wed, 30 Apr 2025 20:40:44 -0700 Subject: [PATCH 59/61] Improving coverage --- tests/chassis_modules_test.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index f53dd7f5bf..5753aea98b 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -2,7 +2,12 @@ import os from click.testing import CliRunner from datetime import datetime, timedelta -# from config.chassis_modules import TRANSITION_TIMEOUT +from config.chassis_modules import ( + set_state_transition_in_progress, + is_transition_timed_out, + shutdown_chassis_module, + TRANSITION_TIMEOUT +) import show.main as show import config.main as config @@ -549,8 +554,8 @@ def test_startup_triggers_transition_tracking(self): print(f"transition_start_time:{fvs['transition_start_time']}") def test_set_state_transition_in_progress_sets_and_removes_timestamp(): - db = MagicMock() - db.statedb = MagicMock() + db = mock.MagicMock() + db.statedb = mock.MagicMock() # Case 1: Set value to 'True' (adds timestamp) db.statedb.get_entry.return_value = {} @@ -576,8 +581,8 @@ def test_set_state_transition_in_progress_sets_and_removes_timestamp(): assert "transition_start_time" not in updated_entry def test_is_transition_timed_out_all_paths(): - db = MagicMock() - db.statedb = MagicMock() + db = mock.MagicMock() + db.statedb = mock.MagicMock() # Case 1: No entry db.statedb.get_entry.return_value = None From 6790820241df03966aac9f380ec41a41767d29bc Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Wed, 30 Apr 2025 20:46:20 -0700 Subject: [PATCH 60/61] Improving coverage --- tests/chassis_modules_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index 5753aea98b..e151cc97a9 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -5,7 +5,6 @@ from config.chassis_modules import ( set_state_transition_in_progress, is_transition_timed_out, - shutdown_chassis_module, TRANSITION_TIMEOUT ) From b981373f2626fe79b478aeb1b8b037b8ba6d99ad Mon Sep 17 00:00:00 2001 From: Ramesh Raghupathy Date: Thu, 1 May 2025 06:34:51 -0700 Subject: [PATCH 61/61] Improving coverage --- tests/chassis_modules_test.py | 41 ++++++++++++----------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index e151cc97a9..c1fd653ecc 100755 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -552,34 +552,30 @@ def test_startup_triggers_transition_tracking(self): print(f"state_transition_in_progress:{fvs['state_transition_in_progress']}") print(f"transition_start_time:{fvs['transition_start_time']}") - def test_set_state_transition_in_progress_sets_and_removes_timestamp(): + def test_set_state_transition_in_progress_sets_and_removes_timestamp(self): db = mock.MagicMock() db.statedb = mock.MagicMock() - # Case 1: Set value to 'True' (adds timestamp) + # Case 1: Set to 'True' adds timestamp db.statedb.get_entry.return_value = {} set_state_transition_in_progress(db, "DPU0", "True") - args = db.statedb.set_entry.call_args[0] - assert args[0] == "CHASSIS_MODULE_TABLE" - assert args[1] == "DPU0" updated_entry = args[2] - assert updated_entry['state_transition_in_progress'] == "True" + assert updated_entry["state_transition_in_progress"] == "True" assert "transition_start_time" in updated_entry - # Case 2: Set value to 'False' (removes timestamp) + # Case 2: Set to 'False' removes timestamp db.statedb.get_entry.return_value = { "state_transition_in_progress": "True", "transition_start_time": "2025-05-01T01:00:00" } set_state_transition_in_progress(db, "DPU0", "False") - args = db.statedb.set_entry.call_args[0] updated_entry = args[2] - assert updated_entry['state_transition_in_progress'] == "False" + assert updated_entry["state_transition_in_progress"] == "False" assert "transition_start_time" not in updated_entry - def test_is_transition_timed_out_all_paths(): + def test_is_transition_timed_out_all_paths(self): db = mock.MagicMock() db.statedb = mock.MagicMock() @@ -591,27 +587,18 @@ def test_is_transition_timed_out_all_paths(): db.statedb.get_entry.return_value = {"state_transition_in_progress": "True"} assert is_transition_timed_out(db, "DPU0") is False - # Case 3: Bad datetime format - db.statedb.get_entry.return_value = { - "state_transition_in_progress": "True", - "transition_start_time": "bad-format" - } + # Case 3: Invalid format + db.statedb.get_entry.return_value = {"transition_start_time": "not-a-date"} assert is_transition_timed_out(db, "DPU0") is False - # Case 4: Timeout exceeded - past_time = (datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=1)).isoformat() - db.statedb.get_entry.return_value = { - "state_transition_in_progress": "True", - "transition_start_time": past_time - } + # Case 4: Timed out + old_time = (datetime.utcnow() - TRANSITION_TIMEOUT - timedelta(seconds=1)).isoformat() + db.statedb.get_entry.return_value = {"transition_start_time": old_time} assert is_transition_timed_out(db, "DPU0") is True - # Case 5: Not yet timed out - recent_time = datetime.utcnow().isoformat() - db.statedb.get_entry.return_value = { - "state_transition_in_progress": "True", - "transition_start_time": recent_time - } + # Case 5: Not timed out yet + now = datetime.utcnow().isoformat() + db.statedb.get_entry.return_value = {"transition_start_time": now} assert is_transition_timed_out(db, "DPU0") is False @classmethod