diff --git a/.changes/unreleased/optimization-20260617-052412.yaml b/.changes/unreleased/optimization-20260617-052412.yaml new file mode 100644 index 000000000..a2d70c437 --- /dev/null +++ b/.changes/unreleased/optimization-20260617-052412.yaml @@ -0,0 +1,6 @@ +kind: optimization +body: Adds validation for backup retention days on SQL DB +time: 2026-06-17T05:24:12.568818136Z +custom: + Author: v-alexmoraru + AuthorLink: https://github.com/v-alexmoraru diff --git a/src/fabric_cli/commands/fs/set/fab_fs_set_item.py b/src/fabric_cli/commands/fs/set/fab_fs_set_item.py index 9d1c61008..704f876fd 100644 --- a/src/fabric_cli/commands/fs/set/fab_fs_set_item.py +++ b/src/fabric_cli/commands/fs/set/fab_fs_set_item.py @@ -8,7 +8,11 @@ from fabric_cli.core import fab_constant from fabric_cli.core.fab_commands import Command from fabric_cli.core.fab_exceptions import FabricCLIError -from fabric_cli.core.fab_types import definition_format_mapping, format_mapping +from fabric_cli.core.fab_types import ( + ItemType, + definition_format_mapping, + format_mapping, +) from fabric_cli.core.hiearchy.fab_hiearchy import Item from fabric_cli.errors.common import CommonErrors from fabric_cli.utils import fab_cmd_set_utils as utils_set @@ -24,6 +28,10 @@ def exec(item: Item, args: Namespace) -> None: utils_set.validate_item_query(query_value, item) + # Validate SQLDatabase-specific properties + if item.item_type == ItemType.SQL_DATABASE: + utils_set.validate_sql_database_property(query_value, args.input) + utils_set.print_set_warning() if force or utils_ui.prompt_confirm(): args.output = None diff --git a/src/fabric_cli/core/fab_constant.py b/src/fabric_cli/core/fab_constant.py index 4fd00e7b9..1420a05ad 100644 --- a/src/fabric_cli/core/fab_constant.py +++ b/src/fabric_cli/core/fab_constant.py @@ -352,3 +352,7 @@ # Invalid query parameters for set command across all fabric resources SET_COMMAND_INVALID_QUERIES = ["id", "type", "workspaceId", "folderId"] +# SQLDatabase property validation +SQL_DATABASE_BACKUP_RETENTION_MIN_DAYS = 1 +SQL_DATABASE_BACKUP_RETENTION_MAX_DAYS = 35 +SQL_DATABASE_BACKUP_RETENTION_PROPERTY = "properties.backupRetentionDays" diff --git a/src/fabric_cli/errors/common.py b/src/fabric_cli/errors/common.py index 6fcfc0009..225f19fb2 100644 --- a/src/fabric_cli/errors/common.py +++ b/src/fabric_cli/errors/common.py @@ -264,3 +264,10 @@ def unsupported_parameter(key: str) -> str: @staticmethod def invalid_parameter_format(param: str) -> str: return f"Invalid parameter format: '{param}'. Use key=value or key!=value." + + @staticmethod + def invalid_backup_retention_days(value: str, min_days: int, max_days: int) -> str: + return ( + f"Invalid backupRetentionDays value '{value}'. " + f"Must be an integer between {min_days} and {max_days} days." + ) diff --git a/src/fabric_cli/utils/fab_cmd_set_utils.py b/src/fabric_cli/utils/fab_cmd_set_utils.py index a947b0823..cc373c6d2 100644 --- a/src/fabric_cli/utils/fab_cmd_set_utils.py +++ b/src/fabric_cli/utils/fab_cmd_set_utils.py @@ -92,6 +92,50 @@ def validate_query_not_in_blocklist( ) +def validate_sql_database_property(query: str, input_value: str) -> None: + """Validate SQLDatabase-specific property values. + + Args: + query: The property query path being set. + input_value: The input value to validate. + + Raises: + FabricCLIError: If the value is invalid for the property. + """ + if query == fab_constant.SQL_DATABASE_BACKUP_RETENTION_PROPERTY: + min_days = fab_constant.SQL_DATABASE_BACKUP_RETENTION_MIN_DAYS + max_days = fab_constant.SQL_DATABASE_BACKUP_RETENTION_MAX_DAYS + + try: + try: + value = int(input_value) + except ValueError: + # Fall back to JSON for encoded values like '7' or '"7"' + parsed = json.loads(input_value) + if isinstance(parsed, bool): + raise ValueError("Booleans are not valid integer values") + elif isinstance(parsed, int): + value = parsed + elif isinstance(parsed, str): + value = int(parsed) + else: + raise ValueError("Value must be an integer") + + # Validate range + if not min_days <= value <= max_days: + raise ValueError("Out of range") + + except (ValueError, TypeError, json.JSONDecodeError): + raise FabricCLIError( + CommonErrors.invalid_backup_retention_days( + str(input_value), + min_days, + max_days, + ), + fab_constant.ERROR_INVALID_INPUT, + ) + + def ensure_notebook_dependency(decoded_item_def: dict, query: str) -> dict: dependency_types = ["lakehouse", "warehouse", "environment"] @@ -194,7 +238,8 @@ def update_cache( def print_set_warning() -> None: - fab_logger.log_warning("Modifying properties may lead to unintended consequences") + fab_logger.log_warning( + "Modifying properties may lead to unintended consequences") def extract_updated_properties(updated_data: dict, query_path: str) -> dict: @@ -260,7 +305,8 @@ def _decode_payload(item_def: dict) -> dict: payload_base64 = part["payload"] if payload_base64: - decoded_payload = base64.b64decode(payload_base64).decode("utf-8") + decoded_payload = base64.b64decode( + payload_base64).decode("utf-8") decoded_payload = json.loads(decoded_payload) # Store the decoded payload part["payload"] = decoded_payload diff --git a/tests/test_commands/recordings/test_commands/test_set/class_setup.yaml b/tests/test_commands/recordings/test_commands/test_set/class_setup.yaml index f3da5c436..1312fd2b1 100644 --- a/tests/test_commands/recordings/test_commands/test_set/class_setup.yaml +++ b/tests/test_commands/recordings/test_commands/test_set/class_setup.yaml @@ -11,7 +11,7 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli/1.6.1 (set; Darwin/25.4.0; Python/3.12.13) + - ms-fabric-cli/1.6.1 (None; Linux/6.12.76-linuxkit; Python/3.12.11) method: GET uri: https://api.fabric.microsoft.com/v1/workspaces response: @@ -26,15 +26,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '2561' + - '3227' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 13 May 2026 11:03:06 GMT + - Tue, 16 Jun 2026 11:09:08 GMT Pragma: - no-cache RequestId: - - 93630144-c10b-421b-9f61-b4c9e96e53ce + - 9b4bbf47-d81b-420e-8f29-be7f7022d3db Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -60,7 +60,7 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli/1.6.1 (set; Darwin/25.4.0; Python/3.12.13) + - ms-fabric-cli/1.6.1 (None; Linux/6.12.76-linuxkit; Python/3.12.11) method: GET uri: https://api.fabric.microsoft.com/v1/workspaces response: @@ -75,15 +75,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '2561' + - '3227' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 13 May 2026 11:03:08 GMT + - Tue, 16 Jun 2026 11:09:09 GMT Pragma: - no-cache RequestId: - - 222a5ebf-a440-4c9b-8a2c-0e1e46b6b6ba + - 7fa2ea2b-8df6-4d7d-806f-ffa179a9b2f7 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -109,7 +109,7 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli/1.6.1 (set; Darwin/25.4.0; Python/3.12.13) + - ms-fabric-cli/1.6.1 (None; Linux/6.12.76-linuxkit; Python/3.12.11) method: GET uri: https://api.fabric.microsoft.com/v1/capacities response: @@ -125,15 +125,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '426' + - '462' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 13 May 2026 11:03:13 GMT + - Tue, 16 Jun 2026 11:09:14 GMT Pragma: - no-cache RequestId: - - dfb69fa0-b455-4808-ae5f-1a7ddef6e34b + - 4aaf4ac5-968d-424b-b2fc-8d0b6cf85d77 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -162,12 +162,12 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli/1.6.1 (set; Darwin/25.4.0; Python/3.12.13) + - ms-fabric-cli/1.6.1 (None; Linux/6.12.76-linuxkit; Python/3.12.11) method: POST uri: https://api.fabric.microsoft.com/v1/workspaces response: body: - string: '{"id": "81517fa4-30e3-42e6-b751-b36af1c8e99a", "displayName": "fabriccli_WorkspacePerTestclass_000001", + string: '{"id": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}' headers: Access-Control-Expose-Headers: @@ -177,17 +177,17 @@ interactions: Content-Encoding: - gzip Content-Length: - - '175' + - '176' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 13 May 2026 11:03:21 GMT + - Tue, 16 Jun 2026 11:09:20 GMT Location: - - https://api.fabric.microsoft.com/v1/workspaces/81517fa4-30e3-42e6-b751-b36af1c8e99a + - https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a Pragma: - no-cache RequestId: - - 6f6fd3f9-2eeb-4e85-afe0-f530855a0a0f + - 143453b7-f98d-4fe3-886b-fcdfbe94253d Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -213,13 +213,13 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli/1.6.1 (set; Darwin/25.4.0; Python/3.12.13) + - ms-fabric-cli/1.6.1 (set; Linux/6.12.76-linuxkit; Python/3.12.11) method: GET uri: https://api.fabric.microsoft.com/v1/workspaces response: body: string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": - "My workspace", "description": "", "type": "Personal"}, {"id": "81517fa4-30e3-42e6-b751-b36af1c8e99a", + "My workspace", "description": "", "type": "Personal"}, {"id": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' headers: @@ -230,15 +230,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '2595' + - '3266' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 13 May 2026 11:03:33 GMT + - Tue, 16 Jun 2026 11:10:55 GMT Pragma: - no-cache RequestId: - - 5a815f03-74e2-4496-aae0-2364a02687cd + - e36eba8a-b837-4f56-b1c2-1afe7bf5bdfc Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -264,9 +264,9 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli/1.6.1 (set; Darwin/25.4.0; Python/3.12.13) + - ms-fabric-cli/1.6.1 (set; Linux/6.12.76-linuxkit; Python/3.12.11) method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/81517fa4-30e3-42e6-b751-b36af1c8e99a/items + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items response: body: string: '{"value": []}' @@ -282,11 +282,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Wed, 13 May 2026 11:03:34 GMT + - Tue, 16 Jun 2026 11:10:56 GMT Pragma: - no-cache RequestId: - - 1283e8eb-846f-49ab-b1e4-4438ef0df0f9 + - 8e6ad6b9-06c4-4219-8a9e-c95d2ad90cca Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -314,9 +314,9 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli/1.6.1 (set; Darwin/25.4.0; Python/3.12.13) + - ms-fabric-cli/1.6.1 (set; Linux/6.12.76-linuxkit; Python/3.12.11) method: DELETE - uri: https://api.fabric.microsoft.com/v1/workspaces/81517fa4-30e3-42e6-b751-b36af1c8e99a + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a response: body: string: '' @@ -332,11 +332,11 @@ interactions: Content-Type: - application/octet-stream Date: - - Wed, 13 May 2026 11:03:35 GMT + - Tue, 16 Jun 2026 11:10:57 GMT Pragma: - no-cache RequestId: - - b0ec7a9f-0f36-4321-9c58-823c5894cd4c + - dfb8c411-66a0-4958-a7fe-8ff070df1400 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: diff --git a/tests/test_commands/recordings/test_commands/test_set/test_set_sql_database_backup_retention_days_invalid_value_failure.yaml b/tests/test_commands/recordings/test_commands/test_set/test_set_sql_database_backup_retention_days_invalid_value_failure.yaml new file mode 100644 index 000000000..875cb25f6 --- /dev/null +++ b/tests/test_commands/recordings/test_commands/test_set/test_set_sql_database_backup_retention_days_invalid_value_failure.yaml @@ -0,0 +1,552 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces + response: + body: + string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": + "My workspace", "description": "", "type": "Personal"}, {"id": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a", + "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "", + "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '3266' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:09:54 GMT + Pragma: + - no-cache + RequestId: + - 7236c1a1-4344-44bb-bedd-988da2e07993 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items + response: + body: + string: '{"value": []}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '32' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:09:55 GMT + Pragma: + - no-cache + RequestId: + - 2eb10b6e-816b-4e5c-b231-6f0c7cc9023d + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items + response: + body: + string: '{"value": []}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '32' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:09:56 GMT + Pragma: + - no-cache + RequestId: + - 54101232-20cf-48c1-ad11-40c35a965765 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: '{"displayName": "fabcli000001", "type": "SQLDatabase", "folderId": null}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '76' + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: POST + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/sqlDatabases + response: + body: + string: 'null' + headers: + Access-Control-Expose-Headers: + - RequestId,Location,Retry-After,ETag,x-ms-operation-id + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '24' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:09:58 GMT + ETag: + - '""' + Location: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/v1/operations/59d8720f-626c-4227-a1dc-773dbdc94806 + Pragma: + - no-cache + RequestId: + - e7bc4872-8c7b-4400-bffd-82b38a338a73 + Retry-After: + - '20' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + x-ms-operation-id: + - 59d8720f-626c-4227-a1dc-773dbdc94806 + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://wabi-us-central-b-primary-redirect.analysis.windows.net/v1/operations/59d8720f-626c-4227-a1dc-773dbdc94806 + response: + body: + string: '{"status": "Succeeded", "createdTimeUtc": "2026-06-16T11:09:57.679029", + "lastUpdatedTimeUtc": "2026-06-16T11:10:12.9882692", "percentComplete": 100, + "error": null}' + headers: + Access-Control-Expose-Headers: + - RequestId,Location,x-ms-operation-id + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '132' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:19 GMT + Location: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/v1/operations/59d8720f-626c-4227-a1dc-773dbdc94806/result + Pragma: + - no-cache + RequestId: + - f26e01d0-a97c-4b22-99e8-1bc9b15308d0 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + x-ms-operation-id: + - 59d8720f-626c-4227-a1dc-773dbdc94806 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://wabi-us-central-b-primary-redirect.analysis.windows.net/v1/operations/59d8720f-626c-4227-a1dc-773dbdc94806/result + response: + body: + string: '{"id": "1d863900-eccc-447a-9cfb-5296cb734648", "type": "SQLDatabase", + "displayName": "fabcli000001", "description": "", "workspaceId": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a"}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Tue, 16 Jun 2026 11:10:19 GMT + Pragma: + - no-cache + RequestId: + - 80b19a02-04d1-4926-bb4f-2fa2fd97a0c6 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces + response: + body: + string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": + "My workspace", "description": "", "type": "Personal"}, {"id": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a", + "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "", + "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '3266' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:20 GMT + Pragma: + - no-cache + RequestId: + - 9ec3a2c7-d17c-4d57-94e4-57c7038252d9 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items + response: + body: + string: '{"value": [{"id": "1d863900-eccc-447a-9cfb-5296cb734648", "type": "SQLDatabase", + "displayName": "fabcli000001", "description": "", "workspaceId": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '170' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:21 GMT + Pragma: + - no-cache + RequestId: + - b45976b4-3bfe-4a34-b9e4-c93715f6699c + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces + response: + body: + string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": + "My workspace", "description": "", "type": "Personal"}, {"id": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a", + "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "", + "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '3266' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:22 GMT + Pragma: + - no-cache + RequestId: + - 3e6605d9-fea6-47c3-84e9-b247f693d5f9 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items + response: + body: + string: '{"value": [{"id": "1d863900-eccc-447a-9cfb-5296cb734648", "type": "SQLDatabase", + "displayName": "fabcli000001", "description": "", "workspaceId": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '170' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:23 GMT + Pragma: + - no-cache + RequestId: + - 26a88061-73fd-4841-8889-461b60cd2688 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: DELETE + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items/1d863900-eccc-447a-9cfb-5296cb734648 + response: + body: + string: '' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '0' + Content-Type: + - application/octet-stream + Date: + - Tue, 16 Jun 2026 11:10:23 GMT + Pragma: + - no-cache + RequestId: + - 5aae77ac-51af-4482-b321-1f39054bdef7 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_commands/recordings/test_commands/test_set/test_set_sql_database_backup_retention_days_out_of_range_failure.yaml b/tests/test_commands/recordings/test_commands/test_set/test_set_sql_database_backup_retention_days_out_of_range_failure.yaml new file mode 100644 index 000000000..bdd4991cb --- /dev/null +++ b/tests/test_commands/recordings/test_commands/test_set/test_set_sql_database_backup_retention_days_out_of_range_failure.yaml @@ -0,0 +1,552 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces + response: + body: + string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": + "My workspace", "description": "", "type": "Personal"}, {"id": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a", + "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "", + "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '3266' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:24 GMT + Pragma: + - no-cache + RequestId: + - ff847db7-9f96-4d56-9c28-3cd937b075e2 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items + response: + body: + string: '{"value": []}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '32' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:25 GMT + Pragma: + - no-cache + RequestId: + - 7771f366-3d69-4c57-992e-89db30c66108 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items + response: + body: + string: '{"value": []}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '32' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:27 GMT + Pragma: + - no-cache + RequestId: + - 48867f01-4d58-47f8-9a35-f5dcd5b8f64f + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: '{"displayName": "fabcli000001", "type": "SQLDatabase", "folderId": null}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '76' + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: POST + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/sqlDatabases + response: + body: + string: 'null' + headers: + Access-Control-Expose-Headers: + - RequestId,Location,Retry-After,ETag,x-ms-operation-id + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '24' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:28 GMT + ETag: + - '""' + Location: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/v1/operations/a685f62a-9aaa-489f-948c-35967b014666 + Pragma: + - no-cache + RequestId: + - 63f15480-bb2a-4ede-8626-a1cde3bc609b + Retry-After: + - '20' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + x-ms-operation-id: + - a685f62a-9aaa-489f-948c-35967b014666 + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://wabi-us-central-b-primary-redirect.analysis.windows.net/v1/operations/a685f62a-9aaa-489f-948c-35967b014666 + response: + body: + string: '{"status": "Succeeded", "createdTimeUtc": "2026-06-16T11:10:28.4106976", + "lastUpdatedTimeUtc": "2026-06-16T11:10:40.2005894", "percentComplete": 100, + "error": null}' + headers: + Access-Control-Expose-Headers: + - RequestId,Location,x-ms-operation-id + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '131' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:49 GMT + Location: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/v1/operations/a685f62a-9aaa-489f-948c-35967b014666/result + Pragma: + - no-cache + RequestId: + - e3de0678-f999-4538-ac0e-6228f8dd238f + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + x-ms-operation-id: + - a685f62a-9aaa-489f-948c-35967b014666 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://wabi-us-central-b-primary-redirect.analysis.windows.net/v1/operations/a685f62a-9aaa-489f-948c-35967b014666/result + response: + body: + string: '{"id": "3d931b64-e790-425a-a1f7-bffd2f2948e6", "type": "SQLDatabase", + "displayName": "fabcli000001", "description": "", "workspaceId": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a"}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Tue, 16 Jun 2026 11:10:50 GMT + Pragma: + - no-cache + RequestId: + - eaf82fc0-8ba4-483b-8bf2-a15b6ed47182 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces + response: + body: + string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": + "My workspace", "description": "", "type": "Personal"}, {"id": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a", + "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "", + "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '3266' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:51 GMT + Pragma: + - no-cache + RequestId: + - 4b9e83a3-23b9-4a04-b738-8845390828e5 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items + response: + body: + string: '{"value": [{"id": "3d931b64-e790-425a-a1f7-bffd2f2948e6", "type": "SQLDatabase", + "displayName": "fabcli000001", "description": "", "workspaceId": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '170' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:52 GMT + Pragma: + - no-cache + RequestId: + - f84c2d51-f8e5-4249-882b-e5eeadc62cf9 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces + response: + body: + string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": + "My workspace", "description": "", "type": "Personal"}, {"id": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a", + "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "", + "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '3266' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:53 GMT + Pragma: + - no-cache + RequestId: + - 23515bb3-60a6-455c-a11d-95ee20c7ddd4 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items + response: + body: + string: '{"value": [{"id": "3d931b64-e790-425a-a1f7-bffd2f2948e6", "type": "SQLDatabase", + "displayName": "fabcli000001", "description": "", "workspaceId": "fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '170' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 16 Jun 2026 11:10:53 GMT + Pragma: + - no-cache + RequestId: + - 9247750c-e518-40f3-858a-2be170098b07 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.6.1 + method: DELETE + uri: https://api.fabric.microsoft.com/v1/workspaces/fd1b2648-dbb2-442c-b4c7-73b02f7f8a2a/items/3d931b64-e790-425a-a1f7-bffd2f2948e6 + response: + body: + string: '' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '0' + Content-Type: + - application/octet-stream + Date: + - Tue, 16 Jun 2026 11:10:54 GMT + Pragma: + - no-cache + RequestId: + - 1e99a1ca-f7e1-46e2-bf60-6ffc5d3681a9 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - deny + home-cluster-uri: + - https://wabi-us-central-b-primary-redirect.analysis.windows.net/ + request-redirected: + - 'true' + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_commands/test_set.py b/tests/test_commands/test_set.py index 386c02041..d9f0cfc52 100644 --- a/tests/test_commands/test_set.py +++ b/tests/test_commands/test_set.py @@ -27,7 +27,6 @@ set_item_metadata_success_params, set_item_metadata_success_params_complete, set_item_metadata_for_all_types_success_item_params, - set_item_metadata_success_params, set_workspace_success_params, set_sparkpool_success_params, set_capacity_success_params, @@ -240,6 +239,66 @@ def test_set_item_variable_library_properties_success( assert "Default value set" in str( mock_questionary_print.call_args[0][0]) + def test_set_sql_database_backup_retention_days_invalid_value_failure( + self, + item_factory, + cli_executor, + assert_fabric_cli_error, + mock_questionary_print, + mock_print_done, + mock_upsert_item_to_cache, + ): + """Test that setting backupRetentionDays with non-integer value fails.""" + # Setup + sql_database = item_factory(ItemType.SQL_DATABASE) + + # Reset mocks + mock_questionary_print.reset_mock() + mock_print_done.reset_mock() + mock_upsert_item_to_cache.reset_mock() + + # Execute command with invalid (non-integer) value + cli_executor.exec_command( + f"set {sql_database.full_path} --query properties.backupRetentionDays --input seven --force" + ) + + # Assert + assert_fabric_cli_error( + constant.ERROR_INVALID_INPUT, + "backupRetentionDays", + ) + mock_upsert_item_to_cache.assert_not_called() + + def test_set_sql_database_backup_retention_days_out_of_range_failure( + self, + item_factory, + cli_executor, + assert_fabric_cli_error, + mock_questionary_print, + mock_print_done, + mock_upsert_item_to_cache, + ): + """Test that setting backupRetentionDays with out-of-range value fails.""" + # Setup + sql_database = item_factory(ItemType.SQL_DATABASE) + + # Reset mocks + mock_questionary_print.reset_mock() + mock_print_done.reset_mock() + mock_upsert_item_to_cache.reset_mock() + + # Execute command with out-of-range value (above max of 35) + cli_executor.exec_command( + f"set {sql_database.full_path} --query properties.backupRetentionDays --input 100 --force" + ) + + # Assert + assert_fabric_cli_error( + constant.ERROR_INVALID_INPUT, + "backupRetentionDays", + ) + mock_upsert_item_to_cache.assert_not_called() + # endregion def test_set_domain_contributors_scope_success( diff --git a/tests/test_utils/test_fab_cmd_set_utils.py b/tests/test_utils/test_fab_cmd_set_utils.py index f3fa6f8ca..da3100aa1 100644 --- a/tests/test_utils/test_fab_cmd_set_utils.py +++ b/tests/test_utils/test_fab_cmd_set_utils.py @@ -205,3 +205,76 @@ def test_update_cache_with_custom_name_key_success(): assert mock_element._name == "New Spark Pool Name" mock_cache_update_func.assert_called_once_with(mock_element) + + +# SQLDatabase validation tests + + +def test_validate_sql_database_property_backup_retention_days_valid_int_success(): + from fabric_cli.utils.fab_cmd_set_utils import validate_sql_database_property + + # Valid integer within range should not raise + validate_sql_database_property("properties.backupRetentionDays", "7") + validate_sql_database_property("properties.backupRetentionDays", "14") + validate_sql_database_property("properties.backupRetentionDays", "21") + validate_sql_database_property("properties.backupRetentionDays", "35") + validate_sql_database_property("properties.backupRetentionDays", "1") + + +def test_validate_sql_database_property_backup_retention_days_out_of_range_failure(): + from fabric_cli.core import fab_constant + from fabric_cli.utils.fab_cmd_set_utils import validate_sql_database_property + + # Value below minimum + with pytest.raises(FabricCLIError) as exc_info: + validate_sql_database_property("properties.backupRetentionDays", "0") + assert exc_info.value.status_code == fab_constant.ERROR_INVALID_INPUT + assert "backupRetentionDays" in str(exc_info.value) + assert "1" in str(exc_info.value) + assert "35" in str(exc_info.value) + + # Value above maximum + with pytest.raises(FabricCLIError) as exc_info: + validate_sql_database_property("properties.backupRetentionDays", "36") + assert exc_info.value.status_code == fab_constant.ERROR_INVALID_INPUT + + +def test_validate_sql_database_property_backup_retention_days_not_integer_failure(): + from fabric_cli.core import fab_constant + from fabric_cli.utils.fab_cmd_set_utils import validate_sql_database_property + + # Non-integer string + with pytest.raises(FabricCLIError) as exc_info: + validate_sql_database_property( + "properties.backupRetentionDays", "seven") + assert exc_info.value.status_code == fab_constant.ERROR_INVALID_INPUT + assert "backupRetentionDays" in str(exc_info.value) + + # Float value + with pytest.raises(FabricCLIError) as exc_info: + validate_sql_database_property("properties.backupRetentionDays", "7.5") + assert exc_info.value.status_code == fab_constant.ERROR_INVALID_INPUT + + # Boolean value + with pytest.raises(FabricCLIError) as exc_info: + validate_sql_database_property( + "properties.backupRetentionDays", "true") + assert exc_info.value.status_code == fab_constant.ERROR_INVALID_INPUT + + +def test_validate_sql_database_property_backup_retention_days_negative_failure(): + from fabric_cli.core import fab_constant + from fabric_cli.utils.fab_cmd_set_utils import validate_sql_database_property + + with pytest.raises(FabricCLIError) as exc_info: + validate_sql_database_property("properties.backupRetentionDays", "-5") + assert exc_info.value.status_code == fab_constant.ERROR_INVALID_INPUT + + +def test_validate_sql_database_property_other_property_no_validation_success(): + from fabric_cli.utils.fab_cmd_set_utils import validate_sql_database_property + + # Other properties should pass without validation + validate_sql_database_property("properties.description", "any value") + validate_sql_database_property("properties.other", "some value") + validate_sql_database_property("displayName", "new name")