diff --git a/fwutil/lib.py b/fwutil/lib.py index 95cced330e..865a748d50 100755 --- a/fwutil/lib.py +++ b/fwutil/lib.py @@ -197,6 +197,9 @@ def get_platform(self): def get_chassis(self): return self.__chassis + def is_smart_switch(self): + return self.__chassis.is_smartswitch() + def is_modular_chassis(self): return len(self.module_component_map) > 0 @@ -535,8 +538,8 @@ def __init__(self, root_path=None): os.mkdir(FIRMWARE_AU_STATUS_DIR) self.__root_path = root_path - - self.__pcp = PlatformComponentsParser(self.is_modular_chassis()) + is_modular_chassis = self.is_modular_chassis() and not self.is_smart_switch() + self.__pcp = PlatformComponentsParser(is_modular_chassis) self.__pcp.parse_platform_components(root_path) self.__validate_platform_schema(self.__pcp) @@ -547,6 +550,9 @@ def __diff_keys(self, keys1, keys2): def __validate_component_map(self, section, pdp_map, pcp_map): diff_keys = self.__diff_keys(list(pdp_map.keys()), list(pcp_map.keys())) + if diff_keys and section == self.SECTION_MODULE and self.is_smart_switch(): + return + if diff_keys: raise RuntimeError( "{} names mismatch: keys={}".format( diff --git a/tests/fwutil_test.py b/tests/fwutil_test.py index 5dd68348b4..1dc1d27313 100644 --- a/tests/fwutil_test.py +++ b/tests/fwutil_test.py @@ -92,5 +92,154 @@ def test_is_capable_auto_update(self): assert CUProvider.is_capable_auto_update('none') == True assert CUProvider.is_capable_auto_update('def') == True + @patch('fwutil.lib.Platform') + @patch('fwutil.lib.PlatformComponentsParser') + @patch('fwutil.lib.ComponentUpdateProvider._ComponentUpdateProvider__validate_platform_schema') + @patch('os.path.isdir', return_value=True) + def test_is_smart_switch_method(self, mock_isdir, mock_validate, + mock_parser_class, mock_platform_class): + """Test that the is_smart_switch method correctly returns True + when the chassis.is_smartswitch() method returns True.""" + # Setup mock chassis + mock_chassis = MagicMock() + mock_chassis.is_smartswitch.return_value = True + + # Setup mock platform + mock_platform = MagicMock() + mock_platform.get_chassis.return_value = mock_chassis + mock_platform_class.return_value = mock_platform + + # Create ComponentUpdateProvider instance + cup = fwutil_lib.ComponentUpdateProvider() + + # Test is_smart_switch method + assert cup.is_smart_switch() + mock_chassis.is_smartswitch.assert_called_once() + + @patch('fwutil.lib.Platform') + @patch('fwutil.lib.PlatformComponentsParser') + @patch('fwutil.lib.ComponentUpdateProvider._ComponentUpdateProvider__validate_platform_schema') + @patch('os.mkdir') + def test_smartswitch_modular_chassis_parsing(self, mock_mkdir, mock_validate, + mock_parser_class, mock_platform_class): + """Test that SmartSwitch devices with modules are passed as non-modular (False) + to the PlatformComponentsParser constructor.""" + # Setup mock chassis that is SmartSwitch and has modules + mock_chassis = MagicMock() + mock_chassis.is_smartswitch.return_value = True + mock_chassis.get_all_modules.return_value = [MagicMock(), MagicMock()] # 2 modules + + # Setup mock platform + mock_platform = MagicMock() + mock_platform.get_chassis.return_value = mock_chassis + mock_platform_class.return_value = mock_platform + + # Setup mock parser + mock_parser = MagicMock() + mock_parser_class.return_value = mock_parser + + # Create ComponentUpdateProvider instance + fwutil_lib.ComponentUpdateProvider() + + # Verify that PlatformComponentsParser was called with is_modular_chassis=False + # because SmartSwitch should be treated as non-modular for parsing purposes + mock_parser_class.assert_called_once_with(False) + + @patch('fwutil.lib.Platform') + @patch('fwutil.lib.PlatformComponentsParser') + @patch('fwutil.lib.ComponentUpdateProvider._ComponentUpdateProvider__validate_platform_schema') + @patch('os.mkdir') + def test_regular_modular_chassis_parsing(self, mock_mkdir, mock_validate, mock_parser_class, mock_platform_class): + """Test that regular modular chassis is treated as modular for parsing""" + # Setup mock chassis that is not SmartSwitch but has modules + mock_chassis = MagicMock() + mock_chassis.is_smartswitch.return_value = False + mock_chassis.get_all_modules.return_value = [MagicMock(), MagicMock()] # 2 modules + + # Setup mock platform + mock_platform = MagicMock() + mock_platform.get_chassis.return_value = mock_chassis + mock_platform_class.return_value = mock_platform + + # Setup mock parser + mock_parser = MagicMock() + mock_parser_class.return_value = mock_parser + + # Create ComponentUpdateProvider instance + fwutil_lib.ComponentUpdateProvider() + + # Verify that PlatformComponentsParser was called with is_modular_chassis=True + # because regular modular chassis should be treated as modular + mock_parser_class.assert_called_once_with(True) + + @patch('fwutil.lib.Platform') + @patch('fwutil.lib.PlatformComponentsParser') + @patch('fwutil.lib.ComponentUpdateProvider._ComponentUpdateProvider__validate_platform_schema') + @patch('os.mkdir') + def test_smartswitch_module_validation_skip(self, mock_mkdir, mock_validate, + mock_parser_class, mock_platform_class): + """Test that module validation is skipped for SmartSwitch platforms""" + # Setup mock chassis that is SmartSwitch + mock_chassis = MagicMock() + mock_chassis.is_smartswitch.return_value = True + mock_chassis.get_all_modules.return_value = [MagicMock()] # Has modules + + # Setup mock platform + mock_platform = MagicMock() + mock_platform.get_chassis.return_value = mock_chassis + mock_platform_class.return_value = mock_platform + + # Setup mock parser + mock_parser = MagicMock() + mock_parser_class.return_value = mock_parser + + # Create ComponentUpdateProvider instance + cup = fwutil_lib.ComponentUpdateProvider() + + # Test that module validation is skipped for SmartSwitch + # This should not raise an exception even if there are differences + pdp_map = {'module1': {'comp1': MagicMock()}} + pcp_map = {'module2': {'comp2': MagicMock()}} # Different modules + + # Should not raise exception for SmartSwitch module validation + cup._ComponentUpdateProvider__validate_component_map( + cup.SECTION_MODULE, pdp_map, pcp_map + ) + + @patch('fwutil.lib.Platform') + @patch('fwutil.lib.PlatformComponentsParser') + @patch('fwutil.lib.ComponentUpdateProvider._ComponentUpdateProvider__validate_platform_schema') + @patch('os.mkdir') + def test_regular_chassis_module_validation_error(self, mock_mkdir, mock_validate, + mock_parser_class, mock_platform_class): + """Test that module validation raises error for regular modular chassis""" + # Setup mock chassis that is not SmartSwitch but has modules + mock_chassis = MagicMock() + mock_chassis.is_smartswitch.return_value = False + mock_chassis.get_all_modules.return_value = [MagicMock()] # Has modules + + # Setup mock platform + mock_platform = MagicMock() + mock_platform.get_chassis.return_value = mock_chassis + mock_platform_class.return_value = mock_platform + + # Setup mock parser + mock_parser = MagicMock() + mock_parser_class.return_value = mock_parser + + # Create ComponentUpdateProvider instance + cup = fwutil_lib.ComponentUpdateProvider() + + # Test that module validation raises error for regular modular chassis + pdp_map = {'module1': {'comp1': MagicMock()}} + pcp_map = {'module2': {'comp2': MagicMock()}} # Different modules + + # Should raise exception for regular modular chassis + with pytest.raises(RuntimeError) as excinfo: + cup._ComponentUpdateProvider__validate_component_map( + cup.SECTION_MODULE, pdp_map, pcp_map + ) + assert "Module names mismatch" in str(excinfo.value) + def teardown(self): print('TEARDOWN')