1313from databricks .labs .blueprint .parallel import Threads
1414from databricks .labs .blueprint .tui import MockPrompts
1515from databricks .labs .blueprint .wheels import ProductInfo
16- from databricks .sdk .errors import InvalidParameterValue , NotFound
16+ from databricks .sdk .errors import AlreadyExists , InvalidParameterValue , NotFound
1717from databricks .sdk .retries import retried
1818from databricks .sdk .service import compute , sql
1919from databricks .sdk .service .iam import PermissionLevel
@@ -38,11 +38,11 @@ def new_installation(ws, sql_backend, env_or_skip, inventory_schema):
3838
3939 def factory (
4040 config_transform : Callable [[WorkspaceConfig ], WorkspaceConfig ] | None = None ,
41+ installation : Installation | None = None ,
4142 product_info : ProductInfo | None = None ,
4243 environ : dict [str , str ] | None = None ,
4344 extend_prompts : dict [str , str ] | None = None ,
44- single_user_install : bool = False ,
45- fresh_install : bool = True ,
45+ inventory_schema_suffix : str = "" ,
4646 ):
4747 if not product_info :
4848 product_info = ProductInfo .for_testing (WorkspaceConfig )
@@ -58,7 +58,7 @@ def factory(
5858 r".*PRO or SERVERLESS SQL warehouse.*" : "1" ,
5959 r"Choose how to map the workspace groups.*" : "1" ,
6060 r".*connect to the external metastore?.*" : "yes" ,
61- r".*Inventory Database.*" : inventory_schema ,
61+ r".*Inventory Database.*" : f" { inventory_schema } { inventory_schema_suffix } " ,
6262 r".*Backup prefix*" : renamed_group_prefix ,
6363 r".*" : "" ,
6464 }
@@ -75,19 +75,8 @@ def factory(
7575 ],
7676 )
7777
78- if not fresh_install :
79- installation = product_info .current_installation (ws )
80- elif single_user_install :
81- installation = Installation (
82- ws ,
83- product_info .product_name (),
84- install_folder = f"/Users/{ ws .current_user .me ().user_name } /.{ product_info .product_name ()} " ,
85- )
86- else :
87- installation = Installation (
88- ws , product_info .product_name (), install_folder = f"/Applications/{ product_info .product_name ()} "
89- )
90-
78+ if not installation :
79+ installation = Installation (ws , product_info .product_name ())
9180 installer = WorkspaceInstaller (prompts , installation , ws , product_info , environ )
9281 workspace_config = installer .configure ()
9382 installation = product_info .current_installation (ws )
@@ -350,31 +339,36 @@ def test_uninstallation(ws, sql_backend, new_installation):
350339 sql_backend .execute (f"show tables from hive_metastore.{ install .config .inventory_database } " )
351340
352341
353- def test_fresh_global_installation (new_installation ):
342+ def test_fresh_global_installation (ws , new_installation ):
354343 product_info = ProductInfo .for_testing (WorkspaceConfig )
355344 global_installation = new_installation (
356345 product_info = product_info ,
346+ installation = Installation .assume_global (ws , product_info .product_name ()),
357347 )
358348 assert global_installation .folder == f"/Applications/{ product_info .product_name ()} "
359349 global_installation .uninstall ()
360350
361351
362352def test_fresh_user_installation (ws , new_installation ):
363353 product_info = ProductInfo .for_testing (WorkspaceConfig )
364- user_installation = new_installation (product_info = product_info , single_user_install = True )
354+ user_installation = new_installation (
355+ product_info = product_info ,
356+ installation = Installation .assume_user_home (ws , product_info .product_name ()),
357+ )
365358 assert user_installation .folder == f"/Users/{ ws .current_user .me ().user_name } /.{ product_info .product_name ()} "
366359 user_installation .uninstall ()
367360
368361
369- def test_global_installation_on_existing_global_install (new_installation ):
362+ def test_global_installation_on_existing_global_install (ws , new_installation ):
370363 product_info = ProductInfo .for_testing (WorkspaceConfig )
371364 existing_global_installation = new_installation (
372365 product_info = product_info ,
366+ installation = Installation .assume_global (ws , product_info .product_name ()),
373367 )
374368 assert existing_global_installation .folder == f"/Applications/{ product_info .product_name ()} "
375369 reinstall_global = new_installation (
376370 product_info = product_info ,
377- fresh_install = False ,
371+ installation = Installation . assume_global ( ws , product_info . product_name ()) ,
378372 )
379373 assert reinstall_global .folder == f"/Applications/{ product_info .product_name ()} "
380374 reinstall_global .uninstall ()
@@ -385,13 +379,14 @@ def test_user_installation_on_existing_global_install(ws, new_installation):
385379 product_info = ProductInfo .for_testing (WorkspaceConfig )
386380 existing_global_installation = new_installation (
387381 product_info = product_info ,
382+ installation = Installation .assume_global (ws , product_info .product_name ()),
388383 )
389384
390385 # warning to be thrown by installer if override environment variable present but no confirmation
391386 with pytest .raises (RuntimeWarning ) as err :
392387 new_installation (
393388 product_info = product_info ,
394- fresh_install = False ,
389+ installation = Installation . assume_global ( ws , product_info . product_name ()) ,
395390 environ = {'UCX_FORCE_INSTALL' : 'user' },
396391 extend_prompts = {
397392 r".*UCX is already installed on this workspace.*" : 'no' ,
@@ -402,11 +397,12 @@ def test_user_installation_on_existing_global_install(ws, new_installation):
402397 # successful override with confirmation
403398 reinstall_user_force = new_installation (
404399 product_info = product_info ,
405- fresh_install = False ,
400+ installation = Installation . assume_global ( ws , product_info . product_name ()) ,
406401 environ = {'UCX_FORCE_INSTALL' : 'user' },
407402 extend_prompts = {
408403 r".*UCX is already installed on this workspace.*" : 'yes' ,
409404 },
405+ inventory_schema_suffix = "_reinstall" ,
410406 )
411407 assert reinstall_user_force .folder == f"/Users/{ ws .current_user .me ().user_name } /.{ product_info .product_name ()} "
412408 reinstall_user_force .uninstall ()
@@ -416,7 +412,9 @@ def test_user_installation_on_existing_global_install(ws, new_installation):
416412def test_global_installation_on_existing_user_install (ws , new_installation ):
417413 # existing installation at user level
418414 product_info = ProductInfo .for_testing (WorkspaceConfig )
419- existing_user_installation = new_installation (product_info = product_info , single_user_install = True )
415+ existing_user_installation = new_installation (
416+ product_info = product_info , installation = Installation .assume_user_home (ws , product_info .product_name ())
417+ )
420418 assert (
421419 existing_user_installation .folder == f"/Users/{ ws .current_user .me ().user_name } /.{ product_info .product_name ()} "
422420 )
@@ -425,7 +423,7 @@ def test_global_installation_on_existing_user_install(ws, new_installation):
425423 with pytest .raises (RuntimeWarning ) as err :
426424 new_installation (
427425 product_info = product_info ,
428- fresh_install = False ,
426+ installation = Installation . assume_user_home ( ws , product_info . product_name ()) ,
429427 environ = {'UCX_FORCE_INSTALL' : 'global' },
430428 extend_prompts = {
431429 r".*UCX is already installed on this workspace.*" : 'no' ,
@@ -434,15 +432,34 @@ def test_global_installation_on_existing_user_install(ws, new_installation):
434432 assert err .value .args [0 ] == "UCX is already installed, but no confirmation"
435433
436434 # not implemented error with confirmation
437-
438435 with pytest .raises (databricks .sdk .errors .NotImplemented ) as err :
439436 new_installation (
440437 product_info = product_info ,
441- fresh_install = False ,
438+ installation = Installation . assume_user_home ( ws , product_info . product_name ()) ,
442439 environ = {'UCX_FORCE_INSTALL' : 'global' },
443440 extend_prompts = {
444441 r".*UCX is already installed on this workspace.*" : 'yes' ,
445442 },
446443 )
447444 assert err .value .args [0 ] == "Migration needed. Not implemented yet."
448445 existing_user_installation .uninstall ()
446+
447+
448+ def test_check_inventory_database_exists (ws , new_installation ):
449+ product_info = ProductInfo .for_testing (WorkspaceConfig )
450+ install = new_installation (
451+ product_info = product_info ,
452+ installation = Installation .assume_global (ws , product_info .product_name ()),
453+ )
454+ inventory_database = install .config .inventory_database
455+
456+ with pytest .raises (AlreadyExists ) as err :
457+ new_installation (
458+ product_info = product_info ,
459+ installation = Installation .assume_global (ws , product_info .product_name ()),
460+ environ = {'UCX_FORCE_INSTALL' : 'user' },
461+ extend_prompts = {
462+ r".*UCX is already installed on this workspace.*" : 'yes' ,
463+ },
464+ )
465+ assert err .value .args [0 ] == f"Inventory database '{ inventory_database } ' already exists in another installation"
0 commit comments