1- from unittest .mock import Mock
1+ from unittest .mock import Mock , call
22
3+ import pytest
34from databricks .sdk .service .iam import Group , ResourceMeta
45
56from databricks .labs .ucx .config import GroupsConfig
67from databricks .labs .ucx .managers .group import GroupManager
78from databricks .labs .ucx .providers .groups_info import MigrationGroupInfo
89
910
11+ def compare (s , t ):
12+ t = list (t ) # make a mutable copy
13+ try :
14+ for elem in s :
15+ t .remove (elem )
16+ except ValueError :
17+ return False
18+ return not t
19+
20+
1021def test_account_groups_should_not_be_considered ():
1122 client = Mock ()
1223 users_group = Group (display_name = "analysts" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
@@ -67,8 +78,6 @@ def test_backup_group_should_not_be_created_if_already_exists():
6778
6879
6980def test_prepare_groups_in_environment_with_one_group_in_conf_should_return_migrationgroupinfo_object ():
70- client = Mock ()
71-
7281 de_group = Group (display_name = "de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
7382 backup_de_group = Group (display_name = "dbr_backup_de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
7483
@@ -78,6 +87,7 @@ def my_side_effect(filter, **kwargs): # noqa: A002,ARG001
7887 elif filter == "displayName eq 'dbr_backup_de'" :
7988 return [backup_de_group ]
8089
90+ client = Mock ()
8191 client .groups .list .side_effect = my_side_effect
8292 client .api_client .do .return_value = {"Resources" : [de_group .as_dict ()]}
8393
@@ -89,7 +99,107 @@ def my_side_effect(filter, **kwargs): # noqa: A002,ARG001
8999 assert manager ._migration_state .groups == [group_info ]
90100
91101
92- def test_prepare_groups_in_environment_with_no_groups_in_conf ():
102+ def test_prepare_groups_in_environment_with_multiple_groups_in_conf_should_return_two_migrationgroupinfo_object ():
103+ de_group = Group (display_name = "de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
104+ ds_group = Group (display_name = "ds" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
105+
106+ backup_de_group = Group (display_name = "dbr_backup_de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
107+ backup_ds_group = Group (display_name = "dbr_backup_ds" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
108+
109+ client = Mock ()
110+
111+ def api_client_side_effect (method , path , query , ** kwargs ): # noqa: ARG001
112+ if query == {
113+ "filter" : "displayName eq 'ds'" ,
114+ "attributes" : "id,displayName,meta,entitlements,roles,members" ,
115+ "excludedAttributes" : None ,
116+ }:
117+ return {"Resources" : [ds_group .as_dict ()]}
118+ elif query == {
119+ "filter" : "displayName eq 'de'" ,
120+ "attributes" : "id,displayName,meta,entitlements,roles,members" ,
121+ "excludedAttributes" : None ,
122+ }:
123+ return {"Resources" : [de_group .as_dict ()]}
124+
125+ client .api_client .do .side_effect = api_client_side_effect
126+
127+ def list_side_effect (filter , ** kwargs ): # noqa: A002,ARG001
128+ if filter == "displayName eq 'de'" :
129+ return [de_group ]
130+ elif filter == "displayName eq 'ds'" :
131+ return [ds_group ]
132+ elif filter == "displayName eq 'dbr_backup_de'" :
133+ return [backup_de_group ]
134+ elif filter == "displayName eq 'dbr_backup_ds'" :
135+ return [backup_ds_group ]
136+
137+ client .groups .list .side_effect = list_side_effect
138+
139+ group_conf = GroupsConfig (selected = ["de" , "ds" ], backup_group_prefix = "dbr_backup_" )
140+ manager = GroupManager (client , group_conf )
141+ manager .prepare_groups_in_environment ()
142+
143+ de_group_info = MigrationGroupInfo (workspace = de_group , account = de_group , backup = backup_de_group )
144+ ds_group_info = MigrationGroupInfo (workspace = ds_group , account = ds_group , backup = backup_ds_group )
145+
146+ assert compare (manager ._migration_state .groups , [ds_group_info , de_group_info ])
147+
148+
149+ def test_prepare_groups_in_environment_should_throw_when_account_group_doesnt_exist ():
150+ de_group = Group (display_name = "de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
151+
152+ client = Mock ()
153+ client .api_client .do .return_value = {}
154+ client .groups .list .return_value = [de_group ]
155+
156+ group_conf = GroupsConfig (selected = ["de" ], backup_group_prefix = "dbr_backup_" )
157+ manager = GroupManager (client , group_conf )
158+
159+ with pytest .raises (AssertionError ) as e_info :
160+ manager .prepare_groups_in_environment ()
161+ assert str (e_info .value ) == "Group de not found on the account level"
162+
163+
164+ def test_prepare_groups_in_environment_should_throw_when_workspace_group_doesnt_exist ():
165+ client = Mock ()
166+ client .api_client .do .return_value = {}
167+ client .groups .list .return_value = []
168+
169+ group_conf = GroupsConfig (selected = ["de" ], backup_group_prefix = "dbr_backup_" )
170+ manager = GroupManager (client , group_conf )
171+
172+ with pytest .raises (AssertionError ) as e_info :
173+ manager .prepare_groups_in_environment ()
174+ assert str (e_info .value ) == "Group de not found on the workspace level"
175+
176+
177+ def test_prepare_groups_in_environment_with_backup_group_not_created_should_create_it ():
178+ de_group = Group (display_name = "de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
179+ backup_de_group = Group (display_name = "dbr_backup_de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
180+
181+ def groups_list_side_effect (filter , ** kwargs ): # noqa: A002,ARG001
182+ if filter == "displayName eq 'de'" :
183+ return [de_group ]
184+ elif filter == "displayName eq 'dbr_backup_de'" :
185+ return []
186+ elif filter == 'displayName ne "users" and displayName ne "admins" and displayName ne "account users"' :
187+ return [de_group ]
188+
189+ client = Mock ()
190+ client .groups .list .side_effect = groups_list_side_effect
191+ client .api_client .do .return_value = {"Resources" : [de_group .as_dict ()]}
192+ client .groups .create .return_value = backup_de_group
193+
194+ group_conf = GroupsConfig (selected = ["de" ], backup_group_prefix = "dbr_backup_" )
195+ manager = GroupManager (client , group_conf )
196+ manager .prepare_groups_in_environment ()
197+
198+ group_info = MigrationGroupInfo (workspace = de_group , account = de_group , backup = backup_de_group )
199+ assert manager ._migration_state .groups == [group_info ]
200+
201+
202+ def test_prepare_groups_in_environment_with_conf_in_auto_mode_should_populate_migrationgroupinfo_object ():
93203 client = Mock ()
94204
95205 de_group = Group (display_name = "de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
@@ -114,6 +224,96 @@ def my_side_effect(filter, **kwargs): # noqa: A002,ARG001
114224 assert manager ._migration_state .groups == [group_info ]
115225
116226
227+ def test_prepare_groups_in_environment_with_conf_in_auto_mode_and_backup_group_exists_should_call_list_and_do ():
228+ client = Mock ()
229+
230+ de_group = Group (display_name = "de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
231+ backup_de_group = Group (display_name = "dbr_backup_de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
232+
233+ def my_side_effect (filter , ** kwargs ): # noqa: A002,ARG001
234+ if filter == "displayName eq 'de'" :
235+ return [de_group ]
236+ elif filter == "displayName eq 'dbr_backup_de'" :
237+ return [backup_de_group ]
238+ elif filter == 'displayName ne "users" and displayName ne "admins" and displayName ne "account users"' :
239+ return [de_group ]
240+
241+ client .groups .list .side_effect = my_side_effect
242+ client .api_client .do .return_value = {"Resources" : [de_group .as_dict ()]}
243+
244+ group_conf = GroupsConfig (backup_group_prefix = "dbr_backup_" , auto = True )
245+ manager = GroupManager (client , group_conf )
246+ manager .prepare_groups_in_environment ()
247+
248+ assert client .mock_calls == [
249+ call .groups .list (
250+ attributes = "displayName,meta" ,
251+ filter = 'displayName ne "users" and displayName ne "admins" and displayName ne "account users"' ,
252+ ),
253+ call .groups .list (attributes = "id,displayName,meta,entitlements,roles,members" , filter = "displayName eq 'de'" ),
254+ call .api_client .do (
255+ "GET" ,
256+ "/api/2.0/account/scim/v2/Groups" ,
257+ query = {
258+ "filter" : "displayName eq 'de'" ,
259+ "attributes" : "id,displayName,meta,entitlements,roles,members" ,
260+ "excludedAttributes" : None ,
261+ },
262+ ),
263+ call .groups .list (
264+ filter = "displayName eq 'dbr_backup_de'" , attributes = "id,displayName,meta,entitlements,roles,members"
265+ ),
266+ ]
267+
268+
269+ def test_prepare_groups_in_environment_with_no_groups_in_conf_and_backup_group_exists_should_make_api_calls ():
270+ client = Mock ()
271+
272+ de_group = Group (display_name = "de" , meta = ResourceMeta (resource_type = "WorkspaceGroup" ))
273+
274+ def my_side_effect (filter , ** kwargs ): # noqa: A002,ARG001
275+ if filter == "displayName eq 'de'" :
276+ return [de_group ]
277+ elif filter == "displayName eq 'dbr_backup_de'" :
278+ return []
279+ elif filter == 'displayName ne "users" and displayName ne "admins" and displayName ne "account users"' :
280+ return [de_group ]
281+
282+ client .groups .list .side_effect = my_side_effect
283+ client .api_client .do .return_value = {"Resources" : [de_group .as_dict ()]}
284+
285+ group_conf = GroupsConfig (backup_group_prefix = "dbr_backup_" , auto = True )
286+ manager = GroupManager (client , group_conf )
287+ manager .prepare_groups_in_environment ()
288+
289+ assert client .mock_calls == [
290+ call .groups .list (
291+ attributes = "displayName,meta" ,
292+ filter = 'displayName ne "users" and displayName ne "admins" and displayName ne "account users"' ,
293+ ),
294+ call .groups .list (attributes = "id,displayName,meta,entitlements,roles,members" , filter = "displayName eq 'de'" ),
295+ call .api_client .do (
296+ "GET" ,
297+ "/api/2.0/account/scim/v2/Groups" ,
298+ query = {
299+ "filter" : "displayName eq 'de'" ,
300+ "attributes" : "id,displayName,meta,entitlements,roles,members" ,
301+ "excludedAttributes" : None ,
302+ },
303+ ),
304+ call .groups .list (
305+ filter = "displayName eq 'dbr_backup_de'" , attributes = "id,displayName,meta,entitlements,roles,members"
306+ ),
307+ call .groups .create (
308+ display_name = "dbr_backup_de" ,
309+ meta = ResourceMeta (resource_type = "WorkspaceGroup" ),
310+ entitlements = None ,
311+ roles = None ,
312+ members = None ,
313+ ),
314+ ]
315+
316+
117317def test_replace_workspace_groups_with_account_groups_should_call_delete_and_do ():
118318 client = Mock ()
119319
0 commit comments