diff --git a/src/azure-cli/azure/cli/command_modules/sql/custom.py b/src/azure-cli/azure/cli/command_modules/sql/custom.py index 4b1c9923dcd..7b93b8e8b96 100644 --- a/src/azure-cli/azure/cli/command_modules/sql/custom.py +++ b/src/azure-cli/azure/cli/command_modules/sql/custom.py @@ -4672,10 +4672,17 @@ def server_update( # Handle soft delete retention days # 0 = disable soft delete, 1-7 = enable with specified retention days - # If not specified, set to None to avoid sending existing value to API if soft_delete_retention_days is not None: instance.retention_days = soft_delete_retention_days + elif instance.retention_days is not None and instance.retention_days < 0: + # Legacy servers may have retention_days=-1 (meaning "not configured"). + # The API now validates this field and rejects negative values, so + # explicitly set to 0 (disabled) to avoid a validation error when + # other server properties are being updated. + instance.retention_days = 0 else: + # If not specified and existing value is valid (0-7) or None, + # set to None to avoid sending the existing value to the API. instance.retention_days = None return instance diff --git a/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py b/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py index 3318425bfe6..70cad0b25d8 100644 --- a/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py +++ b/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py @@ -9409,6 +9409,67 @@ def test_sql_server_soft_delete_complete_recovery_workflow(self, resource_group, # Note: ResourceGroupPreparer automatically handles cleanup of the resource group + +class SqlServerUpdateRetentionDaysUnitTest(unittest.TestCase): + """Unit tests for server_update retention_days handling.""" + + def _make_server_instance(self, retention_days): + """Create a minimal mock server instance with the given retention_days.""" + from unittest.mock import MagicMock + instance = MagicMock() + instance.retention_days = retention_days + instance.identity = None + instance.administrator_login_password = None + instance.minimal_tls_version = None + instance.public_network_access = None + instance.primary_user_assigned_identity_id = None + instance.key_id = None + instance.federated_client_id = None + return instance + + def test_server_update_negative_retention_days_is_reset_to_zero(self): + """ + When server has retention_days=-1 (legacy 'not configured' value) and + --soft-delete-retention-days is NOT passed, server_update should set + retention_days to 0 to avoid 'Invalid value given for parameter RetentionDays' + from the API. + """ + from azure.cli.command_modules.sql.custom import server_update + instance = self._make_server_instance(retention_days=-1) + result = server_update(instance) + self.assertEqual(result.retention_days, 0) + + def test_server_update_valid_retention_days_is_cleared_when_not_specified(self): + """ + When server has a valid retention_days value and --soft-delete-retention-days + is NOT passed, server_update should set retention_days to None (omit from PUT). + """ + from azure.cli.command_modules.sql.custom import server_update + instance = self._make_server_instance(retention_days=5) + result = server_update(instance) + self.assertIsNone(result.retention_days) + + def test_server_update_specified_retention_days_overrides_existing(self): + """ + When --soft-delete-retention-days IS passed, server_update should use + the specified value regardless of the existing value. + """ + from azure.cli.command_modules.sql.custom import server_update + instance = self._make_server_instance(retention_days=-1) + result = server_update(instance, soft_delete_retention_days=3) + self.assertEqual(result.retention_days, 3) + + def test_server_update_zero_specified_retention_days(self): + """ + When --soft-delete-retention-days 0 is passed, server_update should + explicitly disable soft delete by setting retention_days to 0. + """ + from azure.cli.command_modules.sql.custom import server_update + instance = self._make_server_instance(retention_days=7) + result = server_update(instance, soft_delete_retention_days=0) + self.assertEqual(result.retention_days, 0) + + class SqlServerDeletedServerScenarioTest(ScenarioTest): def test_sql_server_restore_non_existent_deleted_server(self):