From 0760396ca6af3faae7a3aa4b872ccc3c4e687d62 Mon Sep 17 00:00:00 2001 From: aviat cohen Date: Tue, 23 Dec 2025 15:57:45 +0000 Subject: [PATCH 1/5] Improve the error message shown when the MPE creator lacks Azure permissions for the target resource. --- .../optimization-20251223-155633.yaml | 3 + .../fab_fs_mkdir_managedprivateendpoint.py | 12 +- .../test_commands/test_mkdir/class_setup.yaml | 62 +-- ...orbidden_azure_access_pending_success.yaml | 409 ++++++++++++++++++ tests/test_commands/test_mkdir.py | 62 +++ 5 files changed, 513 insertions(+), 35 deletions(-) create mode 100644 .changes/unreleased/optimization-20251223-155633.yaml create mode 100644 tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml diff --git a/.changes/unreleased/optimization-20251223-155633.yaml b/.changes/unreleased/optimization-20251223-155633.yaml new file mode 100644 index 00000000..e9451447 --- /dev/null +++ b/.changes/unreleased/optimization-20251223-155633.yaml @@ -0,0 +1,3 @@ +kind: optimization +body: Improve the error message to clearly indicate when the MPE creator does not have sufficient Azure permissions on the resource. +time: 2025-12-23T15:56:33.427481409Z diff --git a/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py b/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py index 890e253d..a8a1f294 100644 --- a/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py +++ b/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py @@ -11,6 +11,7 @@ from fabric_cli.core import fab_constant from fabric_cli.core.fab_exceptions import FabricCLIError from fabric_cli.core.hiearchy.fab_hiearchy import VirtualItem +from fabric_cli.errors import ErrorMessages from fabric_cli.utils import fab_cmd_mkdir_utils as mkdir_utils from fabric_cli.utils import fab_mem_store as utils_mem_store from fabric_cli.utils import fab_ui as utils_ui @@ -86,16 +87,19 @@ def exec(managed_private_endpoint: VirtualItem, args: Namespace) -> None: # Wait exponentially time.sleep(2**iteration) iteration += 1 - except Exception: - state = "Failed" + except Exception as exc: + if exc.status_code =='Forbidden' and exc.message == ErrorMessages.Common.forbidden(): + state = "Pending" + else: + state = "Failed" break - if state != "Succeeded": + if state not in ["Succeeded", "Pending"]: raise FabricCLIError( f"Managed Private Endpoint was created on Fabric but encountered an issue on Azure provisioning. State: {state}", fab_constant.ERROR_OPERATION_FAILED, ) - result_message = f"'{managed_private_endpoint.name}' created" + result_message = f"'{managed_private_endpoint.name}' created. {'Pending approval on Azure side' if state == 'Pending' else ''}" if params.get("autoapproveenabled", "false").lower() == "true": diff --git a/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml b/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml index a6218da0..e92b287c 100644 --- a/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml +++ b/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml @@ -11,7 +11,7 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli/1.1.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.2.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: GET uri: https://api.fabric.microsoft.com/v1/workspaces response: @@ -26,15 +26,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '786' + - '1260' Content-Type: - application/json; charset=utf-8 Date: - - Thu, 25 Sep 2025 09:13:42 GMT + - Tue, 23 Dec 2025 15:40:19 GMT Pragma: - no-cache RequestId: - - 7eaee504-fac2-4c96-8e32-dbef7efe8bde + - 828ac25b-846e-4d51-968b-03ed0644dfca 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.1.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.2.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: GET uri: https://api.fabric.microsoft.com/v1/workspaces response: @@ -75,15 +75,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '786' + - '1260' Content-Type: - application/json; charset=utf-8 Date: - - Thu, 25 Sep 2025 09:13:43 GMT + - Tue, 23 Dec 2025 15:40:26 GMT Pragma: - no-cache RequestId: - - 695ed7dd-2104-488c-b0c0-845f91a5ca01 + - 0c4f6251-ba88-4ca8-91f5-4d517abe2c93 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.1.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.2.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: GET uri: https://api.fabric.microsoft.com/v1/capacities response: @@ -125,15 +125,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '271' + - '874' Content-Type: - application/json; charset=utf-8 Date: - - Thu, 25 Sep 2025 09:13:47 GMT + - Tue, 23 Dec 2025 15:40:32 GMT Pragma: - no-cache RequestId: - - 6d155373-03fd-4f34-8d94-0820e30d54b1 + - 24748e8c-f0de-4592-8dc6-99fafd5d0780 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.1.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.2.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: POST uri: https://api.fabric.microsoft.com/v1/workspaces response: body: - string: '{"id": "d37f35bf-4dce-4291-9812-477382595e4b", "displayName": "fabriccli_WorkspacePerTestclass_000001", + string: '{"id": "dcd810a4-ac00-4552-9616-e21d6588bc17", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}' headers: Access-Control-Expose-Headers: @@ -177,17 +177,17 @@ interactions: Content-Encoding: - gzip Content-Length: - - '188' + - '187' Content-Type: - application/json; charset=utf-8 Date: - - Thu, 25 Sep 2025 09:13:55 GMT + - Tue, 23 Dec 2025 15:40:41 GMT Location: - - https://api.fabric.microsoft.com/v1/workspaces/d37f35bf-4dce-4291-9812-477382595e4b + - https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17 Pragma: - no-cache RequestId: - - 9950b60b-464a-477d-a0ee-0c15c5cdf936 + - e834830a-bd40-4dbb-8d41-4beda90ecb22 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.1.0 (ls; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.2.0 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) 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": "d37f35bf-4dce-4291-9812-477382595e4b", + "My workspace", "description": "", "type": "Personal"}, {"id": "dcd810a4-ac00-4552-9616-e21d6588bc17", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' headers: @@ -230,15 +230,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '820' + - '1290' Content-Type: - application/json; charset=utf-8 Date: - - Thu, 25 Sep 2025 09:14:33 GMT + - Tue, 23 Dec 2025 15:44:02 GMT Pragma: - no-cache RequestId: - - c1d25fd0-3982-4b9e-bf98-dc785f01a79d + - 031eb161-daa7-4243-87d6-dca967f707c0 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.1.0 (ls; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.2.0 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/d37f35bf-4dce-4291-9812-477382595e4b/items + uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/items response: body: string: '{"value": []}' @@ -282,11 +282,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Thu, 25 Sep 2025 09:14:34 GMT + - Tue, 23 Dec 2025 15:44:02 GMT Pragma: - no-cache RequestId: - - 4faadd3b-1048-460e-9bc3-fc8be2360ac1 + - 1b20a02f-599c-493d-9bd8-1836f2ace0c3 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.1.0 (ls; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.2.0 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: DELETE - uri: https://api.fabric.microsoft.com/v1/workspaces/d37f35bf-4dce-4291-9812-477382595e4b + uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17 response: body: string: '' @@ -332,11 +332,11 @@ interactions: Content-Type: - application/octet-stream Date: - - Thu, 25 Sep 2025 09:14:35 GMT + - Tue, 23 Dec 2025 15:44:03 GMT Pragma: - no-cache RequestId: - - 5c18271d-3f2c-4a89-a672-d0707be7a579 + - f9650d40-039d-424b-bf38-6dfaabff6e5d Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: diff --git a/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml b/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml new file mode 100644 index 00000000..808142b9 --- /dev/null +++ b/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml @@ -0,0 +1,409 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.2.0 + 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": "dcd810a4-ac00-4552-9616-e21d6588bc17", + "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created + by fab", "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: + - '1290' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 23 Dec 2025 15:40:52 GMT + Pragma: + - no-cache + RequestId: + - cf23a02d-a3a9-4df6-9184-604252a87600 + 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.2.0 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints + 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, 23 Dec 2025 15:40:53 GMT + Pragma: + - no-cache + RequestId: + - 779d40db-c396-4c9c-b404-80b6e789aa94 + 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.2.0 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints + 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, 23 Dec 2025 15:40:53 GMT + Pragma: + - no-cache + RequestId: + - 693e8f28-eb9f-4d54-b153-495bd34a5b74 + 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: '{"name": "fabcli000001", "targetPrivateLinkResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", + "targetSubresourceType": "sqlServer", "requestMessage": "Created by fab"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '268' + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.2.0 + method: POST + uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints + response: + body: + string: '{"id": "e08bb37a-a86e-4560-8db1-6d2a35e6c81c", "provisioningState": + "Provisioning", "connectionState": {"status": null, "description": null, "actionsRequired": + null}, "name": "fabcli000001", "targetPrivateLinkResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", + "targetSubresourceType": "sqlServer"}' + headers: + Access-Control-Expose-Headers: + - RequestId,Location + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '270' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 23 Dec 2025 15:41:12 GMT + Location: + - https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints/e08bb37a-a86e-4560-8db1-6d2a35e6c81c + Pragma: + - no-cache + RequestId: + - 21c83e74-67db-471a-9768-298046684cbd + 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: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Type: + - application/json + User-Agent: + - ms-fabric-cli-test/1.2.0 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints/e08bb37a-a86e-4560-8db1-6d2a35e6c81c + response: + body: + string: '{"id": "e08bb37a-a86e-4560-8db1-6d2a35e6c81c", "provisioningState": + "Provisioning", "connectionState": {"status": null, "description": null, "actionsRequired": + null}, "name": "fabcli000001", "targetPrivateLinkResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", + "targetSubresourceType": "sqlServer"}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '270' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 23 Dec 2025 15:41:51 GMT + Pragma: + - no-cache + RequestId: + - e9566fbd-6f80-4a7a-b00d-29b841b03449 + 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.2.0 + 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": "dcd810a4-ac00-4552-9616-e21d6588bc17", + "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created + by fab", "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: + - '1290' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 23 Dec 2025 15:44:00 GMT + Pragma: + - no-cache + RequestId: + - 9da5a5c8-86f0-4c72-8aa5-9748ab4f8a2d + 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.2.0 + method: GET + uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints + response: + body: + string: '{"value": [{"id": "e08bb37a-a86e-4560-8db1-6d2a35e6c81c", "provisioningState": + "Succeeded", "connectionState": {"status": "Pending", "description": "Created + by fab", "actionsRequired": "None"}, "name": "fabcli000001", "targetPrivateLinkResourceId": + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", + "targetSubresourceType": "sqlServer"}]}' + headers: + Access-Control-Expose-Headers: + - RequestId + Cache-Control: + - no-store, must-revalidate, no-cache + Content-Encoding: + - gzip + Content-Length: + - '299' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 23 Dec 2025 15:44:00 GMT + Pragma: + - no-cache + RequestId: + - 932f97ec-e0a0-4f2b-a7b2-f62c6c9e3096 + 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.2.0 + method: DELETE + uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints/e08bb37a-a86e-4560-8db1-6d2a35e6c81c + 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, 23 Dec 2025 15:44:01 GMT + Pragma: + - no-cache + RequestId: + - afcc78e9-fe99-483a-84fa-4c2180d3c64a + 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_mkdir.py b/tests/test_commands/test_mkdir.py index b6bcf690..61fd10fe 100644 --- a/tests/test_commands/test_mkdir.py +++ b/tests/test_commands/test_mkdir.py @@ -1168,6 +1168,68 @@ def test_mkdir_managed_private_endpoint_without_params_fail( upsert_managed_private_endpoint_to_cache.assert_not_called() spy_create_managed_private_endpoint.assert_not_called() + def test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success( + self, + workspace, + cli_executor, + mock_print_done, + vcr_instance, + cassette_name, + upsert_managed_private_endpoint_to_cache, + spy_create_managed_private_endpoint, + test_data: StaticTestData, + ): + """Test that when Azure access is forbidden during find_mpe_connection, the state is set to Pending.""" + # Setup + managed_private_endpoint_display_name = generate_random_string( + vcr_instance, cassette_name + ) + type = VirtualItemContainerType.MANAGED_PRIVATE_ENDPOINT + managed_private_endpoint_full_path = cli_path_join( + workspace.full_path, + str(type), + f"{managed_private_endpoint_display_name}.{str(VICMap[type])}", + ) + subscription_id = test_data.azure_subscription_id + resource_group = test_data.azure_resource_group + sql_server = test_data.sql_server.server + + # Create a mock exception that simulates Forbidden access to Azure + class MockForbiddenException(Exception): + def __init__(self): + super().__init__() + self.status_code = "Forbidden" + self.message = ErrorMessages.Common.forbidden() + + # Mock find_mpe_connection to raise Forbidden exception + with patch( + "fabric_cli.utils.fab_cmd_mkdir_utils.find_mpe_connection" + ) as mock_find_mpe: + mock_find_mpe.side_effect = MockForbiddenException() + + # Execute command + cli_executor.exec_command( + f"mkdir {managed_private_endpoint_full_path} -P targetPrivateLinkResourceId=/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Sql/servers/{sql_server},targetSubresourceType=sqlServer" + ) + + # Assert + spy_create_managed_private_endpoint.assert_called_once() + mock_print_done.assert_called_once() + upsert_managed_private_endpoint_to_cache.assert_called_once() + assert ( + managed_private_endpoint_display_name in mock_print_done.call_args[0][0] + ) + assert ( + f"'{managed_private_endpoint_display_name}.{str(VICMap[type])}' created. Pending approval on Azure side" + == mock_print_done.call_args[0][0] + ) + + # Verify that find_mpe_connection was called and threw the forbidden exception + mock_find_mpe.assert_called_once() + + # Cleanup + rm(managed_private_endpoint_full_path) + # endregion # region ExternalDataShare From 3f6aafe81892fa7260684b03ef74c6363d2e7d28 Mon Sep 17 00:00:00 2001 From: aviat cohen Date: Wed, 24 Dec 2025 07:16:00 +0000 Subject: [PATCH 2/5] improve pending message; change condition to or --- .../fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py | 7 +++++-- tests/test_commands/test_mkdir.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py b/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py index a8a1f294..cb0df36a 100644 --- a/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py +++ b/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py @@ -88,7 +88,10 @@ def exec(managed_private_endpoint: VirtualItem, args: Namespace) -> None: time.sleep(2**iteration) iteration += 1 except Exception as exc: - if exc.status_code =='Forbidden' and exc.message == ErrorMessages.Common.forbidden(): + if ( + exc.status_code == fab_constant.ERROR_FORBIDDEN + or exc.message == ErrorMessages.Common.forbidden() + ): state = "Pending" else: state = "Failed" @@ -99,7 +102,7 @@ def exec(managed_private_endpoint: VirtualItem, args: Namespace) -> None: f"Managed Private Endpoint was created on Fabric but encountered an issue on Azure provisioning. State: {state}", fab_constant.ERROR_OPERATION_FAILED, ) - result_message = f"'{managed_private_endpoint.name}' created. {'Pending approval on Azure side' if state == 'Pending' else ''}" + result_message = f"'{managed_private_endpoint.name}' created. {'Private endpoint provisioning in Azure is pending approval' if state == 'Pending' else ''}" if params.get("autoapproveenabled", "false").lower() == "true": diff --git a/tests/test_commands/test_mkdir.py b/tests/test_commands/test_mkdir.py index 61fd10fe..9f1cbbe8 100644 --- a/tests/test_commands/test_mkdir.py +++ b/tests/test_commands/test_mkdir.py @@ -1220,7 +1220,7 @@ def __init__(self): managed_private_endpoint_display_name in mock_print_done.call_args[0][0] ) assert ( - f"'{managed_private_endpoint_display_name}.{str(VICMap[type])}' created. Pending approval on Azure side" + f"'{managed_private_endpoint_display_name}.{str(VICMap[type])}' created. Private endpoint provisioning in Azure is pending approval" == mock_print_done.call_args[0][0] ) From 35c8e7b7f737e105d4e8ffeee5bd61ad9d27347d Mon Sep 17 00:00:00 2001 From: aviat cohen Date: Wed, 24 Dec 2025 08:40:09 +0000 Subject: [PATCH 3/5] fix type check - catch FabricCliError --- .../fab_fs_mkdir_managedprivateendpoint.py | 2 +- .../test_commands/test_mkdir/class_setup.yaml | 44 ++++++------- ...orbidden_azure_access_pending_success.yaml | 62 +++++++++---------- tests/test_commands/test_mkdir.py | 17 ++--- 4 files changed, 59 insertions(+), 66 deletions(-) diff --git a/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py b/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py index cb0df36a..6622bc92 100644 --- a/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py +++ b/src/fabric_cli/commands/fs/mkdir/fab_fs_mkdir_managedprivateendpoint.py @@ -87,7 +87,7 @@ def exec(managed_private_endpoint: VirtualItem, args: Namespace) -> None: # Wait exponentially time.sleep(2**iteration) iteration += 1 - except Exception as exc: + except FabricCLIError as exc: if ( exc.status_code == fab_constant.ERROR_FORBIDDEN or exc.message == ErrorMessages.Common.forbidden() diff --git a/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml b/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml index e92b287c..8b163a87 100644 --- a/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml +++ b/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml @@ -26,15 +26,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1260' + - '1509' Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:40:19 GMT + - Wed, 24 Dec 2025 08:36:47 GMT Pragma: - no-cache RequestId: - - 828ac25b-846e-4d51-968b-03ed0644dfca + - 021c4922-fcfb-4b0c-85fa-b1fb27d0f3fe Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -75,15 +75,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1260' + - '1509' Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:40:26 GMT + - Wed, 24 Dec 2025 08:36:47 GMT Pragma: - no-cache RequestId: - - 0c4f6251-ba88-4ca8-91f5-4d517abe2c93 + - 130a6ffc-a658-419b-8b3f-314ae70647e0 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -129,11 +129,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:40:32 GMT + - Wed, 24 Dec 2025 08:36:52 GMT Pragma: - no-cache RequestId: - - 24748e8c-f0de-4592-8dc6-99fafd5d0780 + - a79373ec-f763-4aba-afc6-025c7a9234ab Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -167,7 +167,7 @@ interactions: uri: https://api.fabric.microsoft.com/v1/workspaces response: body: - string: '{"id": "dcd810a4-ac00-4552-9616-e21d6588bc17", "displayName": "fabriccli_WorkspacePerTestclass_000001", + string: '{"id": "fdd4099e-34b0-4656-afc2-fab5a530bc0a", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}' headers: Access-Control-Expose-Headers: @@ -181,13 +181,13 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:40:41 GMT + - Wed, 24 Dec 2025 08:36:59 GMT Location: - - https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17 + - https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a Pragma: - no-cache RequestId: - - e834830a-bd40-4dbb-8d41-4beda90ecb22 + - 6b63d08c-2122-4757-a854-c045067a9dc4 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -219,7 +219,7 @@ interactions: response: body: string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": - "My workspace", "description": "", "type": "Personal"}, {"id": "dcd810a4-ac00-4552-9616-e21d6588bc17", + "My workspace", "description": "", "type": "Personal"}, {"id": "fdd4099e-34b0-4656-afc2-fab5a530bc0a", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' headers: @@ -230,15 +230,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1290' + - '1535' Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:44:02 GMT + - Wed, 24 Dec 2025 08:38:20 GMT Pragma: - no-cache RequestId: - - 031eb161-daa7-4243-87d6-dca967f707c0 + - 33f29032-1684-422f-89e3-3a4738a7ec9f Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -266,7 +266,7 @@ interactions: User-Agent: - ms-fabric-cli/1.2.0 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/items + uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/items response: body: string: '{"value": []}' @@ -282,11 +282,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:44:02 GMT + - Wed, 24 Dec 2025 08:38:20 GMT Pragma: - no-cache RequestId: - - 1b20a02f-599c-493d-9bd8-1836f2ace0c3 + - 3287a50c-caa0-4c28-ac9e-6cc197855e1f Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -316,7 +316,7 @@ interactions: User-Agent: - ms-fabric-cli/1.2.0 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: DELETE - uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17 + uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a response: body: string: '' @@ -332,11 +332,11 @@ interactions: Content-Type: - application/octet-stream Date: - - Tue, 23 Dec 2025 15:44:03 GMT + - Wed, 24 Dec 2025 08:38:21 GMT Pragma: - no-cache RequestId: - - f9650d40-039d-424b-bf38-6dfaabff6e5d + - 72ee8eb8-2095-443b-aead-6fd39b3287b3 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: diff --git a/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml b/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml index 808142b9..bdad339f 100644 --- a/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml +++ b/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml @@ -17,7 +17,7 @@ interactions: response: body: string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": - "My workspace", "description": "", "type": "Personal"}, {"id": "dcd810a4-ac00-4552-9616-e21d6588bc17", + "My workspace", "description": "", "type": "Personal"}, {"id": "fdd4099e-34b0-4656-afc2-fab5a530bc0a", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' headers: @@ -28,15 +28,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1290' + - '1535' Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:40:52 GMT + - Wed, 24 Dec 2025 08:36:59 GMT Pragma: - no-cache RequestId: - - cf23a02d-a3a9-4df6-9184-604252a87600 + - d0a1b1a7-da65-48b6-8fba-368fc9cd3f51 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -64,7 +64,7 @@ interactions: User-Agent: - ms-fabric-cli-test/1.2.0 method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints + uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints response: body: string: '{"value": []}' @@ -80,11 +80,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:40:53 GMT + - Wed, 24 Dec 2025 08:37:00 GMT Pragma: - no-cache RequestId: - - 779d40db-c396-4c9c-b404-80b6e789aa94 + - 59b6b62b-3a2b-41ea-97d9-af245d87f599 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -112,7 +112,7 @@ interactions: User-Agent: - ms-fabric-cli-test/1.2.0 method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints + uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints response: body: string: '{"value": []}' @@ -128,11 +128,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:40:53 GMT + - Wed, 24 Dec 2025 08:37:00 GMT Pragma: - no-cache RequestId: - - 693e8f28-eb9f-4d54-b153-495bd34a5b74 + - 1f88409f-0327-48af-b340-0af5fb327321 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -163,10 +163,10 @@ interactions: User-Agent: - ms-fabric-cli-test/1.2.0 method: POST - uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints + uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints response: body: - string: '{"id": "e08bb37a-a86e-4560-8db1-6d2a35e6c81c", "provisioningState": + string: '{"id": "6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3", "provisioningState": "Provisioning", "connectionState": {"status": null, "description": null, "actionsRequired": null}, "name": "fabcli000001", "targetPrivateLinkResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", "targetSubresourceType": "sqlServer"}' @@ -182,13 +182,13 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:41:12 GMT + - Wed, 24 Dec 2025 08:37:03 GMT Location: - - https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints/e08bb37a-a86e-4560-8db1-6d2a35e6c81c + - https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints/6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3 Pragma: - no-cache RequestId: - - 21c83e74-67db-471a-9768-298046684cbd + - ec7ef75c-a120-402f-b26a-3bc798690568 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -216,10 +216,10 @@ interactions: User-Agent: - ms-fabric-cli-test/1.2.0 method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints/e08bb37a-a86e-4560-8db1-6d2a35e6c81c + uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints/6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3 response: body: - string: '{"id": "e08bb37a-a86e-4560-8db1-6d2a35e6c81c", "provisioningState": + string: '{"id": "6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3", "provisioningState": "Provisioning", "connectionState": {"status": null, "description": null, "actionsRequired": null}, "name": "fabcli000001", "targetPrivateLinkResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", "targetSubresourceType": "sqlServer"}' @@ -235,11 +235,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:41:51 GMT + - Wed, 24 Dec 2025 08:37:04 GMT Pragma: - no-cache RequestId: - - e9566fbd-6f80-4a7a-b00d-29b841b03449 + - cc3b67ee-55ce-4137-a9e5-3fb509ecdfb1 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -271,7 +271,7 @@ interactions: response: body: string: '{"value": [{"id": "3634a139-2c9e-4205-910b-3b089a31be47", "displayName": - "My workspace", "description": "", "type": "Personal"}, {"id": "dcd810a4-ac00-4552-9616-e21d6588bc17", + "My workspace", "description": "", "type": "Personal"}, {"id": "fdd4099e-34b0-4656-afc2-fab5a530bc0a", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' headers: @@ -282,15 +282,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1290' + - '1535' Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:44:00 GMT + - Wed, 24 Dec 2025 08:38:18 GMT Pragma: - no-cache RequestId: - - 9da5a5c8-86f0-4c72-8aa5-9748ab4f8a2d + - 507ffd6f-47ea-4fd9-92e7-6087aed4dceb Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -318,10 +318,10 @@ interactions: User-Agent: - ms-fabric-cli-test/1.2.0 method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints + uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints response: body: - string: '{"value": [{"id": "e08bb37a-a86e-4560-8db1-6d2a35e6c81c", "provisioningState": + string: '{"value": [{"id": "6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3", "provisioningState": "Succeeded", "connectionState": {"status": "Pending", "description": "Created by fab", "actionsRequired": "None"}, "name": "fabcli000001", "targetPrivateLinkResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", @@ -334,15 +334,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '299' + - '300' Content-Type: - application/json; charset=utf-8 Date: - - Tue, 23 Dec 2025 15:44:00 GMT + - Wed, 24 Dec 2025 08:38:19 GMT Pragma: - no-cache RequestId: - - 932f97ec-e0a0-4f2b-a7b2-f62c6c9e3096 + - a97f44fc-a662-4cc0-8560-ce2e7fbcc098 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -372,7 +372,7 @@ interactions: User-Agent: - ms-fabric-cli-test/1.2.0 method: DELETE - uri: https://api.fabric.microsoft.com/v1/workspaces/dcd810a4-ac00-4552-9616-e21d6588bc17/managedPrivateEndpoints/e08bb37a-a86e-4560-8db1-6d2a35e6c81c + uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints/6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3 response: body: string: '' @@ -388,11 +388,11 @@ interactions: Content-Type: - application/octet-stream Date: - - Tue, 23 Dec 2025 15:44:01 GMT + - Wed, 24 Dec 2025 08:38:19 GMT Pragma: - no-cache RequestId: - - afcc78e9-fe99-483a-84fa-4c2180d3c64a + - 5502a0ff-68bc-48fd-bafa-b2f1f6a2bf97 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: diff --git a/tests/test_commands/test_mkdir.py b/tests/test_commands/test_mkdir.py index 9f1cbbe8..9e68294d 100644 --- a/tests/test_commands/test_mkdir.py +++ b/tests/test_commands/test_mkdir.py @@ -21,6 +21,7 @@ ) from fabric_cli.core import fab_constant as constant from fabric_cli.core import fab_handle_context as handle_context +from fabric_cli.core.fab_exceptions import FabricCLIError from fabric_cli.core.fab_types import ( ItemType, VICMap, @@ -1194,18 +1195,13 @@ def test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success( resource_group = test_data.azure_resource_group sql_server = test_data.sql_server.server - # Create a mock exception that simulates Forbidden access to Azure - class MockForbiddenException(Exception): - def __init__(self): - super().__init__() - self.status_code = "Forbidden" - self.message = ErrorMessages.Common.forbidden() - - # Mock find_mpe_connection to raise Forbidden exception with patch( "fabric_cli.utils.fab_cmd_mkdir_utils.find_mpe_connection" ) as mock_find_mpe: - mock_find_mpe.side_effect = MockForbiddenException() + mock_find_mpe.side_effect = FabricCLIError( + ErrorMessages.Common.forbidden(), + constant.ERROR_FORBIDDEN, + ) # Execute command cli_executor.exec_command( @@ -1216,9 +1212,6 @@ def __init__(self): spy_create_managed_private_endpoint.assert_called_once() mock_print_done.assert_called_once() upsert_managed_private_endpoint_to_cache.assert_called_once() - assert ( - managed_private_endpoint_display_name in mock_print_done.call_args[0][0] - ) assert ( f"'{managed_private_endpoint_display_name}.{str(VICMap[type])}' created. Private endpoint provisioning in Azure is pending approval" == mock_print_done.call_args[0][0] From 437d8dd00a740ca7840a90c4ebc7e4925db4fca7 Mon Sep 17 00:00:00 2001 From: aviat cohen Date: Wed, 24 Dec 2025 10:07:04 +0000 Subject: [PATCH 4/5] verify status_code and message when find_mpe_connection return 403 --- tests/test_utils/test_fab_cmd_mkdir_utils.py | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 tests/test_utils/test_fab_cmd_mkdir_utils.py diff --git a/tests/test_utils/test_fab_cmd_mkdir_utils.py b/tests/test_utils/test_fab_cmd_mkdir_utils.py new file mode 100644 index 00000000..b0fa180a --- /dev/null +++ b/tests/test_utils/test_fab_cmd_mkdir_utils.py @@ -0,0 +1,77 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +from argparse import Namespace +from unittest.mock import Mock, patch + +import pytest + +from fabric_cli.core import fab_constant +from fabric_cli.core.fab_exceptions import FabricCLIError +from fabric_cli.errors import ErrorMessages +from fabric_cli.utils.fab_cmd_mkdir_utils import find_mpe_connection + + +class TestFindMpeConnection: + """Test cases for find_mpe_connection function.""" + + def test_find_mpe_connection_return_403_success(self): + """Test that find_mpe_connection handles 403 forbidden error correctly when session.request returns 403.""" + # Arrange + mock_managed_private_endpoint = Mock() + mock_managed_private_endpoint.workspace.id = "test-workspace-id" + mock_managed_private_endpoint.short_name = "test-mpe-name" + + target_resource_id = "/subscriptions/test-sub/resourceGroups/test-rg/providers/Microsoft.Sql/servers/test-server" + + # Mock the session.request response to return 403 + mock_response = Mock() + mock_response.status_code = 403 + mock_response.text = '{"error": {"code": "Forbidden", "message": "Access denied"}}' + mock_response.headers = {} + + with patch('requests.Session.request') as mock_session_request, \ + patch('fabric_cli.client.fab_api_utils.get_api_version') as mock_get_api_version, \ + patch('fabric_cli.core.fab_auth.FabAuth') as mock_fab_auth_class, \ + patch('fabric_cli.core.fab_context.Context') as mock_fab_context_class: + + mock_session_request.return_value = mock_response + mock_get_api_version.return_value = "2023-11-01" + + # Mock FabAuth().get_access_token(scope) + mock_fab_auth_instance = Mock() + mock_fab_auth_instance.get_access_token.return_value = "mock-access-token" + mock_fab_auth_class.return_value = mock_fab_auth_instance + + # Mock FabContext().command + mock_fab_context_instance = Mock() + mock_fab_context_instance.command = "test-command" + mock_fab_context_class.return_value = mock_fab_context_instance + + # Act & Assert + with pytest.raises(FabricCLIError) as exc_info: + find_mpe_connection(mock_managed_private_endpoint, target_resource_id) + + # Verify the exception details - this tests that do_request properly handles 403 + assert exc_info.value.status_code == fab_constant.ERROR_FORBIDDEN + assert exc_info.value.message == ErrorMessages.Common.forbidden() + + # Verify session.request was called + mock_session_request.assert_called_once() + + # Verify get_api_version was called with the target resource ID + mock_get_api_version.assert_called_once_with(target_resource_id) + + # Verify authentication and context calls + mock_fab_auth_class.assert_called_once() + mock_fab_auth_instance.get_access_token.assert_called_once() + mock_fab_context_class.assert_called_once() + + # Verify the call was made with correct method and URL contains expected parts + call_args = mock_session_request.call_args + assert call_args[1]['method'] == 'get' or call_args.kwargs['method'] == 'get' + # The URL should contain the target resource ID and privateEndpointConnections + called_url = call_args.args[1] if len(call_args.args) > 1 else call_args.kwargs['url'] + assert "privateEndpointConnections" in called_url + assert "api-version=2023-11-01" in called_url + \ No newline at end of file From 59857d3b9d0a2ff9151703ee00f15109871a2781 Mon Sep 17 00:00:00 2001 From: aviat cohen Date: Wed, 24 Dec 2025 11:23:38 +0000 Subject: [PATCH 5/5] fix test after merge --- .../test_commands/test_mkdir/class_setup.yaml | 60 +++++++-------- ...orbidden_azure_access_pending_success.yaml | 76 +++++++++---------- tests/test_commands/test_mkdir.py | 69 +++++++++++------ 3 files changed, 113 insertions(+), 92 deletions(-) diff --git a/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml b/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml index 8b163a87..be90973d 100644 --- a/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml +++ b/tests/test_commands/recordings/test_commands/test_mkdir/class_setup.yaml @@ -11,7 +11,7 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli/1.2.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.3.1 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: GET uri: https://api.fabric.microsoft.com/v1/workspaces response: @@ -26,15 +26,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1509' + - '1662' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:36:47 GMT + - Wed, 24 Dec 2025 11:16:19 GMT Pragma: - no-cache RequestId: - - 021c4922-fcfb-4b0c-85fa-b1fb27d0f3fe + - e9e82624-60b4-40ae-8d9d-f0a28bd1b1b3 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.2.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.3.1 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: GET uri: https://api.fabric.microsoft.com/v1/workspaces response: @@ -75,15 +75,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1509' + - '1662' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:36:47 GMT + - Wed, 24 Dec 2025 11:16:20 GMT Pragma: - no-cache RequestId: - - 130a6ffc-a658-419b-8b3f-314ae70647e0 + - 7d6ce758-a563-429c-9a19-79023b416099 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.2.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.3.1 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: GET uri: https://api.fabric.microsoft.com/v1/capacities response: @@ -129,11 +129,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:36:52 GMT + - Wed, 24 Dec 2025 11:16:23 GMT Pragma: - no-cache RequestId: - - a79373ec-f763-4aba-afc6-025c7a9234ab + - 23ef28a2-85d7-45a7-a94a-0e19f62a4fde 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.2.0 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.3.1 (None; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: POST uri: https://api.fabric.microsoft.com/v1/workspaces response: body: - string: '{"id": "fdd4099e-34b0-4656-afc2-fab5a530bc0a", "displayName": "fabriccli_WorkspacePerTestclass_000001", + string: '{"id": "030399b4-bbf7-4216-b61d-6698ae4292b6", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}' headers: Access-Control-Expose-Headers: @@ -177,17 +177,17 @@ interactions: Content-Encoding: - gzip Content-Length: - - '187' + - '188' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:36:59 GMT + - Wed, 24 Dec 2025 11:16:32 GMT Location: - - https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a + - https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6 Pragma: - no-cache RequestId: - - 6b63d08c-2122-4757-a854-c045067a9dc4 + - 5610440d-2709-49e0-add4-a27a5418d396 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.2.0 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.3.1 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) 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": "fdd4099e-34b0-4656-afc2-fab5a530bc0a", + "My workspace", "description": "", "type": "Personal"}, {"id": "030399b4-bbf7-4216-b61d-6698ae4292b6", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' headers: @@ -230,15 +230,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1535' + - '1693' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:38:20 GMT + - Wed, 24 Dec 2025 11:20:26 GMT Pragma: - no-cache RequestId: - - 33f29032-1684-422f-89e3-3a4738a7ec9f + - 8dc7f29e-0e56-4649-a292-e761d9e72634 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.2.0 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.3.1 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/items + uri: https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6/items response: body: string: '{"value": []}' @@ -282,11 +282,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:38:20 GMT + - Wed, 24 Dec 2025 11:20:31 GMT Pragma: - no-cache RequestId: - - 3287a50c-caa0-4c28-ac9e-6cc197855e1f + - cd256475-316e-4801-814c-e88852073bb3 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.2.0 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) + - ms-fabric-cli/1.3.1 (mkdir; Linux; x86_64; 6.6.87.2-microsoft-standard-WSL2) method: DELETE - uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a + uri: https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6 response: body: string: '' @@ -332,11 +332,11 @@ interactions: Content-Type: - application/octet-stream Date: - - Wed, 24 Dec 2025 08:38:21 GMT + - Wed, 24 Dec 2025 11:20:36 GMT Pragma: - no-cache RequestId: - - 72ee8eb8-2095-443b-aead-6fd39b3287b3 + - b97b5b4b-c4a7-43c8-a192-fece84c53bac Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: diff --git a/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml b/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml index bdad339f..53cc52ca 100644 --- a/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml +++ b/tests/test_commands/recordings/test_commands/test_mkdir/test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success.yaml @@ -11,13 +11,13 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli-test/1.2.0 + - ms-fabric-cli-test/1.3.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": "fdd4099e-34b0-4656-afc2-fab5a530bc0a", + "My workspace", "description": "", "type": "Personal"}, {"id": "030399b4-bbf7-4216-b61d-6698ae4292b6", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' headers: @@ -28,15 +28,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1535' + - '1693' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:36:59 GMT + - Wed, 24 Dec 2025 11:16:32 GMT Pragma: - no-cache RequestId: - - d0a1b1a7-da65-48b6-8fba-368fc9cd3f51 + - 53972d68-e3cd-478d-a495-39cc8cb233be Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -62,9 +62,9 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli-test/1.2.0 + - ms-fabric-cli-test/1.3.1 method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints + uri: https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6/managedPrivateEndpoints response: body: string: '{"value": []}' @@ -80,11 +80,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:37:00 GMT + - Wed, 24 Dec 2025 11:16:33 GMT Pragma: - no-cache RequestId: - - 59b6b62b-3a2b-41ea-97d9-af245d87f599 + - 18a7d9e0-c99b-44f6-b1eb-33b3d499cc11 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -110,9 +110,9 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli-test/1.2.0 + - ms-fabric-cli-test/1.3.1 method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints + uri: https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6/managedPrivateEndpoints response: body: string: '{"value": []}' @@ -128,11 +128,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:37:00 GMT + - Wed, 24 Dec 2025 11:16:33 GMT Pragma: - no-cache RequestId: - - 1f88409f-0327-48af-b340-0af5fb327321 + - 10a38d5a-004c-4cdc-8017-a63309027298 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -161,12 +161,12 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli-test/1.2.0 + - ms-fabric-cli-test/1.3.1 method: POST - uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints + uri: https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6/managedPrivateEndpoints response: body: - string: '{"id": "6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3", "provisioningState": + string: '{"id": "02ac2e30-0261-44b4-8ef2-89faf39e0cd0", "provisioningState": "Provisioning", "connectionState": {"status": null, "description": null, "actionsRequired": null}, "name": "fabcli000001", "targetPrivateLinkResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", "targetSubresourceType": "sqlServer"}' @@ -182,13 +182,13 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:37:03 GMT + - Wed, 24 Dec 2025 11:16:34 GMT Location: - - https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints/6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3 + - https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6/managedPrivateEndpoints/02ac2e30-0261-44b4-8ef2-89faf39e0cd0 Pragma: - no-cache RequestId: - - ec7ef75c-a120-402f-b26a-3bc798690568 + - 3e4d6c51-b9f9-4fe7-b113-392ba108038a Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -214,12 +214,12 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli-test/1.2.0 + - ms-fabric-cli-test/1.3.1 method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints/6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3 + uri: https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6/managedPrivateEndpoints/02ac2e30-0261-44b4-8ef2-89faf39e0cd0 response: body: - string: '{"id": "6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3", "provisioningState": + string: '{"id": "02ac2e30-0261-44b4-8ef2-89faf39e0cd0", "provisioningState": "Provisioning", "connectionState": {"status": null, "description": null, "actionsRequired": null}, "name": "fabcli000001", "targetPrivateLinkResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", "targetSubresourceType": "sqlServer"}' @@ -235,11 +235,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:37:04 GMT + - Wed, 24 Dec 2025 11:16:36 GMT Pragma: - no-cache RequestId: - - cc3b67ee-55ce-4137-a9e5-3fb509ecdfb1 + - ceb20a95-9440-4c73-b4c1-adb3c098ffd8 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -265,13 +265,13 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli-test/1.2.0 + - ms-fabric-cli-test/1.3.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": "fdd4099e-34b0-4656-afc2-fab5a530bc0a", + "My workspace", "description": "", "type": "Personal"}, {"id": "030399b4-bbf7-4216-b61d-6698ae4292b6", "displayName": "fabriccli_WorkspacePerTestclass_000001", "description": "Created by fab", "type": "Workspace", "capacityId": "00000000-0000-0000-0000-000000000004"}]}' headers: @@ -282,15 +282,15 @@ interactions: Content-Encoding: - gzip Content-Length: - - '1535' + - '1693' Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:38:18 GMT + - Wed, 24 Dec 2025 11:18:39 GMT Pragma: - no-cache RequestId: - - 507ffd6f-47ea-4fd9-92e7-6087aed4dceb + - 8437660a-78c1-4f30-a904-b6132545bf55 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -316,12 +316,12 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli-test/1.2.0 + - ms-fabric-cli-test/1.3.1 method: GET - uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints + uri: https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6/managedPrivateEndpoints response: body: - string: '{"value": [{"id": "6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3", "provisioningState": + string: '{"value": [{"id": "02ac2e30-0261-44b4-8ef2-89faf39e0cd0", "provisioningState": "Succeeded", "connectionState": {"status": "Pending", "description": "Created by fab", "actionsRequired": "None"}, "name": "fabcli000001", "targetPrivateLinkResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mocked_fabriccli_resource_group/providers/Microsoft.Sql/servers/mocked_sql_server_server", @@ -338,11 +338,11 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Wed, 24 Dec 2025 08:38:19 GMT + - Wed, 24 Dec 2025 11:18:39 GMT Pragma: - no-cache RequestId: - - a97f44fc-a662-4cc0-8560-ce2e7fbcc098 + - 4b2c8cde-6597-4763-a06c-9385806c31ce Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: @@ -370,9 +370,9 @@ interactions: Content-Type: - application/json User-Agent: - - ms-fabric-cli-test/1.2.0 + - ms-fabric-cli-test/1.3.1 method: DELETE - uri: https://api.fabric.microsoft.com/v1/workspaces/fdd4099e-34b0-4656-afc2-fab5a530bc0a/managedPrivateEndpoints/6cac89b6-7a61-4ddd-a286-c18e3fe4d0b3 + uri: https://api.fabric.microsoft.com/v1/workspaces/030399b4-bbf7-4216-b61d-6698ae4292b6/managedPrivateEndpoints/02ac2e30-0261-44b4-8ef2-89faf39e0cd0 response: body: string: '' @@ -388,11 +388,11 @@ interactions: Content-Type: - application/octet-stream Date: - - Wed, 24 Dec 2025 08:38:19 GMT + - Wed, 24 Dec 2025 11:20:14 GMT Pragma: - no-cache RequestId: - - 5502a0ff-68bc-48fd-bafa-b2f1f6a2bf97 + - 0743ac6c-dca1-476d-8eca-ef0464977416 Strict-Transport-Security: - max-age=31536000; includeSubDomains X-Content-Type-Options: diff --git a/tests/test_commands/test_mkdir.py b/tests/test_commands/test_mkdir.py index acb04f42..e7f1de8e 100644 --- a/tests/test_commands/test_mkdir.py +++ b/tests/test_commands/test_mkdir.py @@ -1214,7 +1214,7 @@ def test_mkdir_managed_private_endpoint_forbidden_azure_access_pending_success( mock_print_done.assert_called_once() upsert_managed_private_endpoint_to_cache.assert_called_once() assert ( - f"'{managed_private_endpoint_display_name}.{str(VICMap[type])}' created. Private endpoint provisioning in Azure is pending approval" + f"'{managed_private_endpoint_display_name}.{str(VICMap[type])}' created. Private endpoint provisioning in Azure is pending approval\n" == mock_print_done.call_args[0][0] ) @@ -1371,10 +1371,13 @@ def test_mkdir_connection_with_onpremises_gateway_params_success( # Assert mock_print_done.assert_called() assert mock_print_done.call_count == 1 - assert f"'{connection_display_name}.Connection' created\n" == mock_print_done.call_args[0][0] + assert ( + f"'{connection_display_name}.Connection' created\n" + == mock_print_done.call_args[0][0] + ) mock_print_done.reset_mock() - + # Cleanup rm(connection_full_path) @@ -1394,13 +1397,16 @@ def test_mkdir_connection_with_onpremises_gateway_params_ignore_params_success( ) cli_executor.exec_command( - f"mkdir {connection_full_path} -P gatewayId={test_data.onpremises_gateway_details.id},connectionDetails.type=SQL,connectivityType=OnPremisesGateway,connectionDetails.parameters.server={test_data.sql_server.server}.database.windows.net,connectionDetails.parameters.database={test_data.sql_server.database},credentialDetails.type=Basic,credentialDetails.values='[{{\"gatewayId\":\"{test_data.onpremises_gateway_details.id}\",\"encryptedCredentials\":\"{test_data.onpremises_gateway_details.encrypted_credentials}\",\"ignoreParameters\":\"ignoreParameters\"}}]'" + f'mkdir {connection_full_path} -P gatewayId={test_data.onpremises_gateway_details.id},connectionDetails.type=SQL,connectivityType=OnPremisesGateway,connectionDetails.parameters.server={test_data.sql_server.server}.database.windows.net,connectionDetails.parameters.database={test_data.sql_server.database},credentialDetails.type=Basic,credentialDetails.values=\'[{{"gatewayId":"{test_data.onpremises_gateway_details.id}","encryptedCredentials":"{test_data.onpremises_gateway_details.encrypted_credentials}","ignoreParameters":"ignoreParameters"}}]\'' ) # Assert mock_print_done.assert_called() assert mock_print_done.call_count == 1 - assert f"'{connection_display_name}.Connection' created\n" == mock_print_done.call_args[0][0] + assert ( + f"'{connection_display_name}.Connection' created\n" + == mock_print_done.call_args[0][0] + ) mock_print_warning.assert_called() assert mock_print_warning.call_count == 1 @@ -1409,7 +1415,6 @@ def test_mkdir_connection_with_onpremises_gateway_params_ignore_params_success( # Cleanup rm(connection_full_path) - def test_mkdir_connection_with_onpremises_gateway_params_failure( self, cli_executor, @@ -1452,7 +1457,7 @@ def test_mkdir_connection_with_onpremises_gateway_params_failure( # Test 3: Execute command with missing encryptedCredentials params in one of the values cli_executor.exec_command( - f"mkdir {connection_full_path} -P gatewayId={test_data.onpremises_gateway_details.id},connectionDetails.type=SQL,connectivityType=OnPremisesGateway,connectionDetails.parameters.server={test_data.sql_server.server}.database.windows.net,connectionDetails.parameters.database={test_data.sql_server.database},credentialDetails.type=Basic,credentialDetails.values='[{{\"gatewayId\":\"{test_data.onpremises_gateway_details.id}\",\"encryptedCredentials\":\"{test_data.onpremises_gateway_details.encrypted_credentials}\"}},{{\"encryptedCredentials\":\"{test_data.onpremises_gateway_details.encrypted_credentials}\"}}]'" + f'mkdir {connection_full_path} -P gatewayId={test_data.onpremises_gateway_details.id},connectionDetails.type=SQL,connectivityType=OnPremisesGateway,connectionDetails.parameters.server={test_data.sql_server.server}.database.windows.net,connectionDetails.parameters.database={test_data.sql_server.database},credentialDetails.type=Basic,credentialDetails.values=\'[{{"gatewayId":"{test_data.onpremises_gateway_details.id}","encryptedCredentials":"{test_data.onpremises_gateway_details.encrypted_credentials}"}},{{"encryptedCredentials":"{test_data.onpremises_gateway_details.encrypted_credentials}"}}]\'' ) # Assert @@ -1812,38 +1817,36 @@ def test_mkdir_workspace_verify_stderr_stdout_messages_json_format_success( # endregion # region Folders - + def test_mkdir_item_in_folder_listing_success( self, workspace, cli_executor, mock_print_done, mock_questionary_print, mock_fab_set_state_config, vcr_instance, cassette_name ): # Enable folder listing mock_fab_set_state_config(constant.FAB_FOLDER_LISTING_ENABLED, "true") - # Setup folder_name = f"{generate_random_string(vcr_instance, cassette_name)}.Folder" folder_full_path = cli_path_join(workspace.full_path, folder_name) - + # Create folder cli_executor.exec_command(f"mkdir {folder_full_path}") mock_print_done.assert_called_once() mock_print_done.reset_mock() - + # Create notebook in folder notebook_name = f"{generate_random_string(vcr_instance, cassette_name)}.Notebook" notebook_full_path = cli_path_join(folder_full_path, notebook_name) cli_executor.exec_command(f"mkdir {notebook_full_path}") - + # Verify notebook appears in folder listing cli_executor.exec_command(f"ls {folder_full_path}") printed_output = mock_questionary_print.call_args[0][0] assert notebook_name in printed_output - + # Cleanup rm(notebook_full_path) rm(folder_full_path) - def test_mkdir_folder_success(self, workspace, cli_executor, mock_print_done): # Setup folder_display_name = "folder" @@ -1897,7 +1900,13 @@ def test_mkdir_folder_name_already_exists_failure( # region Batch Output Tests def test_mkdir_single_item_creation_batch_output_structure_success( - self, workspace, cli_executor, mock_print_done, mock_questionary_print, vcr_instance, cassette_name + self, + workspace, + cli_executor, + mock_print_done, + mock_questionary_print, + vcr_instance, + cassette_name, ): """Test that single item creation uses batched output structure.""" # Setup @@ -1919,13 +1928,13 @@ def test_mkdir_single_item_creation_batch_output_structure_success( # Look for the table output with headers output_calls = [str(call) for call in mock_questionary_print.mock_calls] table_output = "\n".join(output_calls) - + # Check for standard table headers assert "id" in table_output or "ID" in table_output assert "type" in table_output or "Type" in table_output assert "displayName" in table_output or "DisplayName" in table_output assert "workspaceId" in table_output or "WorkspaceId" in table_output - + # Check for actual values assert lakehouse_display_name in table_output assert "Lakehouse" in table_output @@ -1934,7 +1943,13 @@ def test_mkdir_single_item_creation_batch_output_structure_success( rm(lakehouse_full_path) def test_mkdir_dependency_creation_batched_output_kql_database_success( - self, workspace, cli_executor, mock_print_done, mock_questionary_print, vcr_instance, cassette_name + self, + workspace, + cli_executor, + mock_print_done, + mock_questionary_print, + vcr_instance, + cassette_name, ): """Test that KQL Database creation with EventHouse dependency produces batched output.""" # Setup @@ -1950,30 +1965,36 @@ def test_mkdir_dependency_creation_batched_output_kql_database_success( # The current implementation may still have separate calls, but data should be collected assert mock_print_done.call_count >= 1 - # Verify both items are mentioned in output all_calls = [call.args[0] for call in mock_print_done.call_args_list] all_output = " ".join(all_calls) - assert f"'{kqldatabase_display_name}_auto.{ItemType.EVENTHOUSE.value}' and '{kqldatabase_display_name}.{ItemType.KQL_DATABASE.value}' created" in all_output + assert ( + f"'{kqldatabase_display_name}_auto.{ItemType.EVENTHOUSE.value}' and '{kqldatabase_display_name}.{ItemType.KQL_DATABASE.value}' created" + in all_output + ) # Verify headers and values in mock_questionary_print.mock_calls for batched output output_calls = [str(call) for call in mock_questionary_print.mock_calls] table_output = "\n".join(output_calls) - + # Check for standard table headers (should appear once for consolidated table) assert "id" in table_output or "ID" in table_output assert "type" in table_output or "Type" in table_output assert "displayName" in table_output or "DisplayName" in table_output assert "workspaceId" in table_output or "WorkspaceId" in table_output - + # Check for both item values in the output assert kqldatabase_display_name in table_output - assert f"{kqldatabase_display_name}_auto" in table_output # EventHouse dependency name + assert ( + f"{kqldatabase_display_name}_auto" in table_output + ) # EventHouse dependency name assert "KQLDatabase" in table_output or "KQL_DATABASE" in table_output assert "Eventhouse" in table_output or "EVENTHOUSE" in table_output # Cleanup - removing parent eventhouse removes the kqldatabase as well - eventhouse_full_path = kqldatabase_full_path.removesuffix(".KQLDatabase") + "_auto.Eventhouse" + eventhouse_full_path = ( + kqldatabase_full_path.removesuffix(".KQLDatabase") + "_auto.Eventhouse" + ) rm(eventhouse_full_path) # endregion