55import pytest
66from unittest import mock
77
8- from azure .cli .command_modules .role .custom import _resolve_role_id , _search_role_assignments
8+ from azure .cli .command_modules .role .custom import (
9+ _resolve_role_id , _search_role_assignments , _get_role_definition_id
10+ )
911
1012# pylint: disable=line-too-long
1113
1214
15+ class TestGetRoleDefinitionId :
16+ """Tests for _get_role_definition_id helper function."""
17+
18+ @pytest .mark .parametrize ("resource_id,expected" , [
19+ # Tenant-scoped format
20+ ('/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7' ,
21+ 'acdd72a7-3385-48ef-bd42-f606fba81ae7' ),
22+ # Subscription-scoped format
23+ ('/subscriptions/sub1/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' ,
24+ 'b24988ac-6180-42a0-ab88-20f7382dd24c' ),
25+ # None returns None
26+ (None , None ),
27+ ])
28+ def test_extracts_guid_from_role_definition_id (self , resource_id , expected ):
29+ """Extracts the GUID from various role definition ID formats."""
30+ assert _get_role_definition_id (resource_id ) == expected
31+
32+
1333class TestResolveRoleId :
1434 """Tests for _resolve_role_id function."""
1535
@@ -80,7 +100,7 @@ def _create_assignment(scope, role_definition_id, principal_id='principal-1'):
80100 @pytest .mark .parametrize ("scope,role_def_format" , [
81101 # Root scope with tenant-format role definition ID
82102 ('/' , '/providers/Microsoft.Authorization/roleDefinitions/{guid}' ),
83- # Management group scope with tenant-format role definition ID
103+ # Management group scope with tenant-format role definition ID
84104 ('/providers/Microsoft.Management/managementGroups/my-mg' ,
85105 '/providers/Microsoft.Authorization/roleDefinitions/{guid}' ),
86106 # Subscription scope with subscription-format role definition ID
@@ -123,104 +143,6 @@ def test_different_role_guid_does_not_match(self, mock_clients):
123143
124144 assert len (result ) == 0
125145
126- def test_scope_comparison_is_case_insensitive (self , mock_clients ):
127- """Scope matching is case insensitive."""
128- assignments_client , definitions_client = mock_clients
129- role_def_id = '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7'
130-
131- assignments_client .list_for_scope .return_value = [
132- self ._create_assignment ('/Subscriptions/SUB1/ResourceGroups/RG1' , role_def_id ),
133- ]
134-
135- result = _search_role_assignments (
136- assignments_client , definitions_client ,
137- scope = '/subscriptions/sub1/resourcegroups/rg1' ,
138- assignee_object_id = None , role = None ,
139- include_inherited = False , include_groups = False
140- )
141-
142- assert len (result ) == 1
143-
144- def test_include_inherited_returns_parent_scope_assignments (self , mock_clients ):
145- """include_inherited=True returns assignments at and above the scope."""
146- assignments_client , definitions_client = mock_clients
147- role_def_id = '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7'
148-
149- assignments_client .list_for_scope .return_value = [
150- self ._create_assignment ('/' , role_def_id , 'principal-1' ),
151- self ._create_assignment ('/subscriptions/sub1' , role_def_id , 'principal-2' ),
152- ]
153-
154- result = _search_role_assignments (
155- assignments_client , definitions_client ,
156- scope = '/subscriptions/sub1' ,
157- assignee_object_id = None , role = None ,
158- include_inherited = True , include_groups = False
159- )
160-
161- assert len (result ) == 2
162-
163- def test_include_inherited_false_filters_parent_scope (self , mock_clients ):
164- """include_inherited=False filters out assignments at parent scopes."""
165- assignments_client , definitions_client = mock_clients
166- role_def_id = '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7'
167-
168- assignments_client .list_for_scope .return_value = [
169- self ._create_assignment ('/' , role_def_id , 'principal-1' ),
170- self ._create_assignment ('/subscriptions/sub1' , role_def_id , 'principal-2' ),
171- ]
172-
173- result = _search_role_assignments (
174- assignments_client , definitions_client ,
175- scope = '/subscriptions/sub1' ,
176- assignee_object_id = None , role = None ,
177- include_inherited = False , include_groups = False
178- )
179-
180- assert len (result ) == 1
181- assert result [0 ].principal_id == 'principal-2'
182-
183- def test_assignee_filter (self , mock_clients ):
184- """assignee_object_id filters assignments by principal."""
185- assignments_client , definitions_client = mock_clients
186- role_def_id = '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7'
187-
188- assignments_client .list_for_scope .return_value = [
189- self ._create_assignment ('/subscriptions/sub1' , role_def_id , 'principal-1' ),
190- self ._create_assignment ('/subscriptions/sub1' , role_def_id , 'principal-2' ),
191- ]
192-
193- result = _search_role_assignments (
194- assignments_client , definitions_client ,
195- scope = '/subscriptions/sub1' ,
196- assignee_object_id = 'principal-1' , role = None ,
197- include_inherited = False , include_groups = False
198- )
199-
200- assert len (result ) == 1
201- assert result [0 ].principal_id == 'principal-1'
202-
203- def test_no_scope_uses_subscription_api (self , mock_clients ):
204- """When scope is None, list_for_subscription is called and all assignments returned."""
205- assignments_client , definitions_client = mock_clients
206- role_def_id = '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7'
207-
208- assignments_client .list_for_subscription .return_value = [
209- self ._create_assignment ('/subscriptions/sub1' , role_def_id , 'principal-1' ),
210- self ._create_assignment ('/subscriptions/sub1/resourceGroups/rg1' , role_def_id , 'principal-2' ),
211- ]
212-
213- result = _search_role_assignments (
214- assignments_client , definitions_client ,
215- scope = None ,
216- assignee_object_id = None , role = None ,
217- include_inherited = False , include_groups = False
218- )
219-
220- assert len (result ) == 2
221- assignments_client .list_for_subscription .assert_called_once ()
222- assignments_client .list_for_scope .assert_not_called ()
223-
224146 def test_none_role_definition_id_is_skipped (self , mock_clients ):
225147 """Assignments with None role_definition_id are skipped when filtering by role."""
226148 assignments_client , definitions_client = mock_clients
@@ -238,4 +160,4 @@ def test_none_role_definition_id_is_skipped(self, mock_clients):
238160 )
239161
240162 assert len (result ) == 1
241- assert result [0 ].role_definition_id is not None
163+ assert result [0 ].role_definition_id is not None
0 commit comments