From 646d3c891d5348796746a454e4ce34a728df56d7 Mon Sep 17 00:00:00 2001 From: Gabriel Cocenza Date: Tue, 23 Jan 2024 21:43:36 -0300 Subject: [PATCH] - fixing unit tests --- cou/apps/auxiliary.py | 2 +- tests/unit/apps/test_auxiliary.py | 88 +- tests/unit/apps/test_auxiliary_subordinate.py | 21 +- tests/unit/apps/test_channel_based.py | 39 +- tests/unit/apps/test_core.py | 13 +- tests/unit/apps/test_factory.py | 3 +- tests/unit/apps/test_subordinate.py | 35 +- tests/unit/conftest.py | 765 +++++++++--------- tests/unit/steps/test_steps_analyze.py | 60 +- tests/unit/steps/test_steps_plan.py | 14 +- 10 files changed, 573 insertions(+), 467 deletions(-) diff --git a/cou/apps/auxiliary.py b/cou/apps/auxiliary.py index 82adb1ab..2d55143c 100644 --- a/cou/apps/auxiliary.py +++ b/cou/apps/auxiliary.py @@ -185,7 +185,7 @@ def pre_upgrade_plan(self, target: OpenStackRelease) -> list[PreUpgradeStep]: return super().pre_upgrade_plan(target) -@AppFactory.register_application(["mysql-innodb-cluster"]) +@AppFactory.register_application(["mysql_innodb_cluster"]) class MysqlInnodbClusterApplication(OpenStackAuxiliaryApplication): """Application for mysql-innodb-cluster charm.""" diff --git a/tests/unit/apps/test_auxiliary.py b/tests/unit/apps/test_auxiliary.py index 7dbb2cc7..3b8f7c1f 100644 --- a/tests/unit/apps/test_auxiliary.py +++ b/tests/unit/apps/test_auxiliary.py @@ -33,14 +33,14 @@ from tests.unit.apps.utils import add_steps -def test_auxiliary_app(status, config, model): +def test_auxiliary_app(status, config, model, apps_machines): # version 3.8 on rabbitmq can be from ussuri to yoga. In that case it will be set as yoga. expected_units = [ ApplicationUnit( name="rabbitmq-server/0", os_version=OpenStackRelease("yoga"), workload_version="3.8", - machine="0/lxd/19", + machine=apps_machines["rmq"]["0/lxd/19"], ) ] @@ -50,6 +50,7 @@ def test_auxiliary_app(status, config, model): config["auxiliary_ussuri"], model, "rabbitmq-server", + apps_machines["rmq"], ) assert app.channel == "3.8/stable" assert app.is_valid_track(app.channel) is True @@ -61,13 +62,13 @@ def test_auxiliary_app(status, config, model): assert app.current_os_release == "yoga" -def test_auxiliary_app_cs(status, config, model): +def test_auxiliary_app_cs(status, config, model, apps_machines): expected_units = [ ApplicationUnit( name="rabbitmq-server/0", os_version=OpenStackRelease("yoga"), workload_version="3.8", - machine="0/lxd/19", + machine=apps_machines["rmq"]["0/lxd/19"], ) ] rmq_status = status["rabbitmq_server"] @@ -79,6 +80,7 @@ def test_auxiliary_app_cs(status, config, model): config["auxiliary_ussuri"], model, "rabbitmq-server", + apps_machines["rmq"], ) assert app.channel == "stable" assert app.is_valid_track(app.channel) is True @@ -89,7 +91,9 @@ def test_auxiliary_app_cs(status, config, model): assert app.current_os_release == "yoga" -def test_auxiliary_upgrade_plan_ussuri_to_victoria_change_channel(status, config, model): +def test_auxiliary_upgrade_plan_ussuri_to_victoria_change_channel( + status, config, model, apps_machines +): target = OpenStackRelease("victoria") app = RabbitMQServer( "rabbitmq-server", @@ -97,6 +101,7 @@ def test_auxiliary_upgrade_plan_ussuri_to_victoria_change_channel(status, config config["auxiliary_ussuri"], model, "rabbitmq-server", + apps_machines["rmq"], ) upgrade_plan = app.generate_upgrade_plan(target) @@ -149,7 +154,7 @@ def test_auxiliary_upgrade_plan_ussuri_to_victoria_change_channel(status, config assert upgrade_plan == expected_plan -def test_auxiliary_upgrade_plan_ussuri_to_victoria(status, config, model): +def test_auxiliary_upgrade_plan_ussuri_to_victoria(status, config, model, apps_machines): target = OpenStackRelease("victoria") rmq_status = status["rabbitmq_server"] # rabbitmq already on channel 3.9 on ussuri @@ -160,6 +165,7 @@ def test_auxiliary_upgrade_plan_ussuri_to_victoria(status, config, model): config["auxiliary_ussuri"], model, "rabbitmq-server", + apps_machines["rmq"], ) upgrade_plan = app.generate_upgrade_plan(target) @@ -207,7 +213,9 @@ def test_auxiliary_upgrade_plan_ussuri_to_victoria(status, config, model): assert upgrade_plan == expected_plan -def test_auxiliary_upgrade_plan_ussuri_to_victoria_ch_migration(status, config, model): +def test_auxiliary_upgrade_plan_ussuri_to_victoria_ch_migration( + status, config, model, apps_machines +): target = OpenStackRelease("victoria") rmq_status = status["rabbitmq_server"] rmq_status.charm = "cs:amd64/focal/rabbitmq-server-638" @@ -218,6 +226,7 @@ def test_auxiliary_upgrade_plan_ussuri_to_victoria_ch_migration(status, config, config["auxiliary_ussuri"], model, "rabbitmq-server", + apps_machines["rmq"], ) upgrade_plan = app.generate_upgrade_plan(target) expected_plan = ApplicationUpgradePlan( @@ -268,7 +277,7 @@ def test_auxiliary_upgrade_plan_ussuri_to_victoria_ch_migration(status, config, assert upgrade_plan == expected_plan -def test_auxiliary_upgrade_plan_unknown_track(status, config, model): +def test_auxiliary_upgrade_plan_unknown_track(status, config, model, apps_machines): rmq_status = status["rabbitmq_server"] # 2.0 is an unknown track rmq_status.charm_channel = "2.0/stable" @@ -279,10 +288,13 @@ def test_auxiliary_upgrade_plan_unknown_track(status, config, model): config["auxiliary_ussuri"], model, "rabbitmq-server", + apps_machines["rmq"], ) -def test_auxiliary_app_unknown_version_raise_ApplicationError(status, config, model): +def test_auxiliary_app_unknown_version_raise_ApplicationError( + status, config, model, apps_machines +): with pytest.raises(ApplicationError): RabbitMQServer( "rabbitmq-server", @@ -290,10 +302,11 @@ def test_auxiliary_app_unknown_version_raise_ApplicationError(status, config, mo config["auxiliary_ussuri"], model, "rabbitmq-server", + apps_machines["rmq"], ) -def test_auxiliary_raise_error_unknown_series(status, config, model): +def test_auxiliary_raise_error_unknown_series(status, config, model, apps_machines): app_status = status["rabbitmq_server"] app_status.series = "foo" with pytest.raises(ApplicationError): @@ -303,10 +316,11 @@ def test_auxiliary_raise_error_unknown_series(status, config, model): config["auxiliary_ussuri"], model, "rabbitmq-server", + apps_machines["rmq"], ) -def test_auxiliary_raise_error_os_not_on_lookup(status, config, model, mocker): +def test_auxiliary_raise_error_os_not_on_lookup(status, config, model, mocker, apps_machines): # change OpenStack release to a version that is not on openstack_to_track_mapping.csv mocker.patch( "cou.apps.core.OpenStackApplication.current_os_release", @@ -320,12 +334,13 @@ def test_auxiliary_raise_error_os_not_on_lookup(status, config, model, mocker): config["auxiliary_ussuri"], model, "rabbitmq-server", + apps_machines["rmq"], ) with pytest.raises(ApplicationError): app.possible_current_channels -def test_auxiliary_raise_halt_upgrade(status, config, model): +def test_auxiliary_raise_halt_upgrade(status, config, model, apps_machines): target = OpenStackRelease("victoria") # source is already configured to wallaby, so the plan halt with target victoria app = RabbitMQServer( @@ -334,12 +349,13 @@ def test_auxiliary_raise_halt_upgrade(status, config, model): config["auxiliary_wallaby"], model, "rabbitmq-server", + apps_machines["rmq"], ) with pytest.raises(HaltUpgradePlanGeneration): app.generate_upgrade_plan(target) -def test_auxiliary_no_suitable_channel(status, config, model): +def test_auxiliary_no_suitable_channel(status, config, model, apps_machines): # OPENSTACK_TO_TRACK_MAPPING can't find a track for rabbitmq, focal, zed. target = OpenStackRelease("zed") app_status = status["rabbitmq_server"] @@ -350,19 +366,21 @@ def test_auxiliary_no_suitable_channel(status, config, model): config["auxiliary_wallaby"], model, "rabbitmq-server", + apps_machines["rmq"], ) with pytest.raises(ApplicationError): app.target_channel(target) -def test_ceph_mon_app(status, config, model): +def test_ceph_mon_app(status, config, model, apps_machines): """Test the correctness of instantiating CephMonApplication.""" app = CephMonApplication( "ceph-mon", - status["ceph-mon_xena"], + status["ceph_mon_pacific"], config["auxiliary_xena"], model, "ceph-mon", + apps_machines["ceph-mon"], ) assert app.channel == "pacific/stable" assert app.os_origin == "cloud:focal-xena" @@ -371,7 +389,7 @@ def test_ceph_mon_app(status, config, model): name="ceph-mon/0", os_version=OpenStackRelease("xena"), workload_version="16.2.0", - machine="7", + machine=apps_machines["ceph-mon"]["6"], ) ] assert app.apt_source_codename == "xena" @@ -379,19 +397,16 @@ def test_ceph_mon_app(status, config, model): assert app.is_subordinate is False -def test_ceph_mon_upgrade_plan_xena_to_yoga( - status, - config, - model, -): +def test_ceph_mon_upgrade_plan_xena_to_yoga(status, config, model, apps_machines): """Test when ceph version changes between os releases.""" target = OpenStackRelease("yoga") app = CephMonApplication( "ceph-mon", - status["ceph-mon_xena"], + status["ceph_mon_pacific"], config["auxiliary_xena"], model, "ceph-mon", + apps_machines["ceph-mon"], ) upgrade_plan = app.generate_upgrade_plan(target) @@ -452,15 +467,17 @@ def test_ceph_mon_upgrade_plan_ussuri_to_victoria( status, config, model, + apps_machines, ): """Test when ceph version remains the same between os releases.""" target = OpenStackRelease("victoria") app = CephMonApplication( "ceph-mon", - status["ceph-mon_ussuri"], + status["ceph_mon_octopus"], config["auxiliary_ussuri"], model, "ceph-mon", + apps_machines["ceph-mon"], ) upgrade_plan = app.generate_upgrade_plan(target) @@ -511,13 +528,14 @@ def test_ceph_mon_upgrade_plan_ussuri_to_victoria( assert upgrade_plan == expected_plan -def test_ovn_principal(status, config, model): +def test_ovn_principal(status, config, model, apps_machines): app = OvnPrincipalApplication( "ovn-central", - status["ovn_central_ussuri_22"], + status["ovn_central_22"], config["auxiliary_ussuri"], model, "ovn-central", + apps_machines["ovn-central"], ) assert app.channel == "22.03/stable" assert app.os_origin == "distro" @@ -527,7 +545,7 @@ def test_ovn_principal(status, config, model): assert app.is_subordinate is False -def test_ovn_workload_ver_lower_than_22_principal(status, config, model): +def test_ovn_workload_ver_lower_than_22_principal(status, config, model, apps_machines): target = OpenStackRelease("victoria") exp_error_msg_ovn_upgrade = ( @@ -539,10 +557,11 @@ def test_ovn_workload_ver_lower_than_22_principal(status, config, model): app_ovn_central = OvnPrincipalApplication( "ovn-central", - status["ovn_central_ussuri_20"], + status["ovn_central_20"], config["auxiliary_ussuri"], model, "ovn-central", + apps_machines["ovn-central"], ) with pytest.raises(ApplicationError, match=exp_error_msg_ovn_upgrade): @@ -550,8 +569,8 @@ def test_ovn_workload_ver_lower_than_22_principal(status, config, model): @pytest.mark.parametrize("channel", ["55.7", "19.03"]) -def test_ovn_no_compatible_os_release(status, config, model, channel): - ovn_central_status = status["ovn_central_ussuri_22"] +def test_ovn_no_compatible_os_release(status, config, model, channel, apps_machines): + ovn_central_status = status["ovn_central_22"] ovn_central_status.charm_channel = channel with pytest.raises(ApplicationError): OvnPrincipalApplication( @@ -560,17 +579,19 @@ def test_ovn_no_compatible_os_release(status, config, model, channel): config["auxiliary_ussuri"], model, "ovn-central", + apps_machines["ovn-central"], ) -def test_ovn_principal_upgrade_plan(status, config, model): +def test_ovn_principal_upgrade_plan(status, config, model, apps_machines): target = OpenStackRelease("victoria") app = OvnPrincipalApplication( "ovn-central", - status["ovn_central_ussuri_22"], + status["ovn_central_22"], config["auxiliary_ussuri"], model, "ovn-central", + apps_machines["ovn-central"], ) upgrade_plan = app.generate_upgrade_plan(target) @@ -618,15 +639,16 @@ def test_ovn_principal_upgrade_plan(status, config, model): assert upgrade_plan == expected_plan -def test_mysql_innodb_cluster_upgrade(status, config, model): +def test_mysql_innodb_cluster_upgrade(status, config, model, apps_machines): target = OpenStackRelease("victoria") # source is already configured to wallaby, so the plan halt with target victoria app = MysqlInnodbClusterApplication( "mysql-innodb-cluster", - status["mysql-innodb-cluster"], + status["mysql_innodb_cluster"], config["auxiliary_ussuri"], model, "mysql-innodb-cluster", + apps_machines["mysql-innodb-cluster"], ) upgrade_plan = app.generate_upgrade_plan(target) expected_plan = ApplicationUpgradePlan( diff --git a/tests/unit/apps/test_auxiliary_subordinate.py b/tests/unit/apps/test_auxiliary_subordinate.py index e728e899..19dad9d1 100644 --- a/tests/unit/apps/test_auxiliary_subordinate.py +++ b/tests/unit/apps/test_auxiliary_subordinate.py @@ -57,11 +57,7 @@ def test_auxiliary_subordinate_upgrade_plan_to_victoria(apps, model): def test_ovn_subordinate(status, model): app = OvnSubordinateApplication( - "ovn-chassis", - status["ovn_chassis_ussuri_22"], - {}, - model, - "ovn-chassis", + "ovn-chassis", status["ovn_chassis_focal_22"], {}, model, "ovn-chassis", {} ) assert app.channel == "22.03/stable" assert app.os_origin == "" @@ -83,10 +79,11 @@ def test_ovn_workload_ver_lower_than_22_subordinate(status, model): app_ovn_chassis = OvnSubordinateApplication( "ovn-chassis", - status["ovn_chassis_ussuri_20"], + status["ovn_chassis_focal_20"], {}, model, "ovn-chassis", + {}, ) with pytest.raises(ApplicationError, match=exp_error_msg_ovn_upgrade): @@ -97,10 +94,11 @@ def test_ovn_subordinate_upgrade_plan(status, model): target = OpenStackRelease("victoria") app = OvnSubordinateApplication( "ovn-chassis", - status["ovn_chassis_ussuri_22"], + status["ovn_chassis_focal_22"], {}, model, "ovn-chassis", + {}, ) upgrade_plan = app.generate_upgrade_plan(target) @@ -125,7 +123,7 @@ def test_ovn_subordinate_upgrade_plan_cant_upgrade_charm(status, model): # ovn chassis 22.03 is considered yoga. If it's not necessary to upgrade # the charm code, there is no steps to upgrade. target = OpenStackRelease("victoria") - app_status = status["ovn_chassis_ussuri_22"] + app_status = status["ovn_chassis_focal_22"] app_status.can_upgrade_to = "" app = OvnSubordinateApplication( "ovn-chassis", @@ -133,6 +131,7 @@ def test_ovn_subordinate_upgrade_plan_cant_upgrade_charm(status, model): {}, model, "ovn-chassis", + {}, ) expected_plan = ApplicationUpgradePlan( @@ -149,10 +148,11 @@ def test_ceph_dashboard_upgrade_plan_ussuri_to_victoria(status, config, model): target = OpenStackRelease("victoria") app = OpenStackAuxiliarySubordinateApplication( "ceph-dashboard", - status["ceph_dashboard_ussuri"], + status["ceph_dashboard_octopus"], config["auxiliary_ussuri"], model, "ceph-dashboard", + {}, ) upgrade_plan = app.generate_upgrade_plan(target) @@ -178,10 +178,11 @@ def test_ceph_dashboard_upgrade_plan_xena_to_yoga(status, config, model): target = OpenStackRelease("yoga") app = OpenStackAuxiliarySubordinateApplication( "ceph-dashboard", - status["ceph_dashboard_xena"], + status["ceph_dashboard_pacific"], config["auxiliary_xena"], model, "ceph-dashboard", + {}, ) upgrade_plan = app.generate_upgrade_plan(target) diff --git a/tests/unit/apps/test_channel_based.py b/tests/unit/apps/test_channel_based.py index 886c9e8b..74b06831 100644 --- a/tests/unit/apps/test_channel_based.py +++ b/tests/unit/apps/test_channel_based.py @@ -22,71 +22,78 @@ from tests.unit.apps.utils import add_steps -def test_application_versionless(status, config, model): +def test_application_versionless(status, config, model, apps_machines): app = OpenStackChannelBasedApplication( "glance-simplestreams-sync", - status["glance_simplestreams_sync_ussuri"], + status["glance_simplestreams_sync_focal_ussuri"], config["openstack_ussuri"], model, "glance-simplestreams-sync", + apps_machines["glance-simplestreams-sync"], ) assert app.current_os_release == "ussuri" assert app.is_versionless is True -def test_application_gnocchi_ussuri(status, config, model): +def test_application_gnocchi_ussuri(status, config, model, apps_machines): app = OpenStackChannelBasedApplication( "gnocchi", - status["gnocchi_ussuri"], + status["gnocchi_focal_ussuri"], config["openstack_ussuri"], model, "gnocchi", + apps_machines["gnocchi"], ) assert app.current_os_release == "ussuri" assert app.is_versionless is False -def test_application_gnocchi_xena(status, config, model): +def test_application_gnocchi_xena(status, config, model, apps_machines): # workload version is the same for xena and yoga, but current_os_release # is based on the channel. app = OpenStackChannelBasedApplication( "gnocchi", - status["gnocchi_xena"], + status["gnocchi_focal_xena"], config["openstack_xena"], model, "gnocchi", + apps_machines["gnocchi"], ) assert app.current_os_release == "xena" assert app.is_versionless is False -def test_application_designate_bind_ussuri(status, config, model): +def test_application_designate_bind_ussuri(status, config, model, apps_machines): # workload version is the same from ussuri to yoga, but current_os_release # is based on the channel. app_config = config["openstack_ussuri"] app_config["action-managed-upgrade"] = {"value": False} app = OpenStackChannelBasedApplication( "designate-bind", - status["designate_bind_ussuri"], + status["designate_bind_focal_ussuri"], app_config, model, "designate-bind", + apps_machines["designate-bind"], ) assert app.current_os_release == "ussuri" assert app.is_versionless is False -def test_application_versionless_upgrade_plan_ussuri_to_victoria(status, config, model): +def test_application_versionless_upgrade_plan_ussuri_to_victoria( + status, config, model, apps_machines +): target = OpenStackRelease("victoria") app_config = config["openstack_ussuri"] # Does not have action-managed-upgrade app_config.pop("action-managed-upgrade") app = OpenStackChannelBasedApplication( "glance-simplestreams-sync", - status["glance_simplestreams_sync_ussuri"], + status["glance_simplestreams_sync_focal_ussuri"], app_config, model, "glance-simplestreams-sync", + apps_machines["glance-simplestreams-sync"], ) upgrade_plan = app.generate_upgrade_plan(target) @@ -131,17 +138,18 @@ def test_application_versionless_upgrade_plan_ussuri_to_victoria(status, config, assert upgrade_plan == expected_plan -def test_application_gnocchi_upgrade_plan_ussuri_to_victoria(status, config, model): +def test_application_gnocchi_upgrade_plan_ussuri_to_victoria(status, config, model, apps_machines): # Gnocchi from ussuri to victoria upgrade the workload version from 4.3.4 to 4.4.0. target = OpenStackRelease("victoria") app_config = config["openstack_ussuri"] app_config["action-managed-upgrade"] = {"value": False} app = OpenStackChannelBasedApplication( "gnocchi", - status["gnocchi_ussuri"], + status["gnocchi_focal_ussuri"], app_config, model, "gnocchi", + apps_machines["gnocchi"], ) upgrade_plan = app.generate_upgrade_plan(target) @@ -196,16 +204,19 @@ def test_application_gnocchi_upgrade_plan_ussuri_to_victoria(status, config, mod assert upgrade_plan == expected_plan -def test_application_designate_bind_upgrade_plan_ussuri_to_victoria(status, config, model): +def test_application_designate_bind_upgrade_plan_ussuri_to_victoria( + status, config, model, apps_machines +): target = OpenStackRelease("victoria") app_config = config["openstack_ussuri"] app_config["action-managed-upgrade"] = {"value": False} app = OpenStackChannelBasedApplication( "designate-bind", - status["designate_bind_ussuri"], + status["designate_bind_focal_ussuri"], app_config, model, "designate-bind", + apps_machines["designate-bind"], ) upgrade_plan = app.generate_upgrade_plan(target) diff --git a/tests/unit/apps/test_core.py b/tests/unit/apps/test_core.py index 5343e728..8315fc25 100644 --- a/tests/unit/apps/test_core.py +++ b/tests/unit/apps/test_core.py @@ -165,7 +165,8 @@ def test_application_different_wl(status, config, model, apps_machines): r"'ussuri': \['keystone\/0', 'keystone\/1'\], 'victoria': \['keystone\/2'\]. " "This is not currently handled." ) - app_status = status["keystone_focal_ussuri_victoria"] + app_status = status["keystone_focal_ussuri"] + app_status.units["keystone/2"].workload_version = "18.1.0" app_config = config["openstack_ussuri"] app = Keystone( @@ -178,7 +179,10 @@ def test_application_different_wl(status, config, model, apps_machines): def test_application_cs(status, config, units, model, apps_machines): """Test when application is from charm store.""" target = OpenStackRelease("victoria") - app_status = status["keystone_focal_ussuri_cs"] + + app_status = status["keystone_focal_ussuri"] + app_status.charm = "cs:amd64/focal/keystone-638" + app_config = config["openstack_ussuri"] exp_os_origin = "distro" exp_units = units["units_ussuri"] @@ -436,7 +440,10 @@ def test_upgrade_plan_ussuri_to_victoria(status, config, model, apps_machines): def test_upgrade_plan_ussuri_to_victoria_ch_migration(status, config, model, apps_machines): target = OpenStackRelease("victoria") - app_status = status["keystone_focal_ussuri_cs"] + + app_status = status["keystone_focal_ussuri"] + app_status.charm = "cs:amd64/focal/keystone-638" + app_config = config["openstack_ussuri"] app = Keystone( "my_keystone", app_status, app_config, model, "keystone", apps_machines["keystone"] diff --git a/tests/unit/apps/test_factory.py b/tests/unit/apps/test_factory.py index 194ceb1c..1f97f614 100644 --- a/tests/unit/apps/test_factory.py +++ b/tests/unit/apps/test_factory.py @@ -25,6 +25,7 @@ def test_app_factory_not_supported_openstack_charm(mock_is_charm_supported): config=MagicMock(), model=MagicMock(), charm=charm, + machines=MagicMock(), ) assert my_app is None mock_is_charm_supported.assert_called_once_with(charm) @@ -40,7 +41,7 @@ def __init__(self, *_, **__): pass assert charm in factory.AppFactory.charms - foo = factory.AppFactory.create("my-foo", MagicMock(), {}, MagicMock(), charm) + foo = factory.AppFactory.create("my-foo", MagicMock(), {}, MagicMock(), charm, MagicMock()) mock_is_charm_supported.assert_called_once_with(charm) assert foo is not None assert isinstance(foo, Foo) diff --git a/tests/unit/apps/test_subordinate.py b/tests/unit/apps/test_subordinate.py index 4afda24c..3562cf50 100644 --- a/tests/unit/apps/test_subordinate.py +++ b/tests/unit/apps/test_subordinate.py @@ -26,9 +26,9 @@ def test_post_init(status, model): - app_status = status["keystone-ldap"] + app_status = status["keystone_ldap_focal_ussuri"] app = OpenStackSubordinateApplication( - "my_keystone_ldap", app_status, {}, model, "keystone-ldap" + "my_keystone_ldap", app_status, {}, model, "keystone-ldap", {} ) assert app.channel == "ussuri/stable" assert app.charm_origin == "ch" @@ -37,18 +37,18 @@ def test_post_init(status, model): def test_current_os_release(status, model): - app_status = status["keystone-ldap"] + app_status = status["keystone_ldap_focal_ussuri"] app = OpenStackSubordinateApplication( - "my_keystone_ldap", app_status, {}, model, "keystone-ldap" + "my_keystone_ldap", app_status, {}, model, "keystone-ldap", {} ) assert app.current_os_release == OpenStackRelease("ussuri") def test_generate_upgrade_plan(status, model): target = OpenStackRelease("victoria") - app_status = status["keystone-ldap"] + app_status = status["keystone_ldap_focal_ussuri"] app = OpenStackSubordinateApplication( - "my_keystone_ldap", app_status, {}, model, "keystone-ldap" + "my_keystone_ldap", app_status, {}, model, "keystone-ldap", {} ) upgrade_plan = app.generate_upgrade_plan(target) @@ -84,9 +84,9 @@ def test_generate_upgrade_plan(status, model): ], ) def test_channel_setter_valid(status, model, channel): - app_status = status["keystone-ldap"] + app_status = status["keystone_ldap_focal_ussuri"] app = OpenStackSubordinateApplication( - "my_keystone_ldap", app_status, {}, model, "keystone-ldap" + "my_keystone_ldap", app_status, {}, model, "keystone-ldap", {} ) app.channel = channel @@ -103,10 +103,12 @@ def test_channel_setter_valid(status, model, channel): ], ) def test_channel_setter_invalid(status, model, channel): - app_status = status["keystone-ldap"] + app_status = status["keystone_ldap_focal_ussuri"] app_status.charm_channel = channel with pytest.raises(ApplicationError): - OpenStackSubordinateApplication("my_keystone_ldap", app_status, {}, model, "keystone-ldap") + OpenStackSubordinateApplication( + "my_keystone_ldap", app_status, {}, model, "keystone-ldap", {} + ) @pytest.mark.parametrize( @@ -119,9 +121,10 @@ def test_channel_setter_invalid(status, model, channel): ) def test_generate_plan_ch_migration(status, model, channel): target = OpenStackRelease("wallaby") - app_status = status["keystone-ldap-cs"] + app_status = status["keystone_ldap_focal_ussuri"] + app_status.charm = "cs:amd64/focal/keystone-ldap-437" app = OpenStackSubordinateApplication( - "my_keystone_ldap", app_status, {}, model, "keystone-ldap" + "my_keystone_ldap", app_status, {}, model, "keystone-ldap", {} ) app.channel = channel @@ -157,9 +160,9 @@ def test_generate_plan_ch_migration(status, model, channel): ], ) def test_generate_plan_from_to(status, model, from_os, to_os): - app_status = status["keystone-ldap"] + app_status = status["keystone_ldap_focal_ussuri"] app = OpenStackSubordinateApplication( - "my_keystone_ldap", app_status, {}, model, "keystone-ldap" + "my_keystone_ldap", app_status, {}, model, "keystone-ldap", {} ) app.channel = f"{from_os}/stable" @@ -194,9 +197,9 @@ def test_generate_plan_from_to(status, model, from_os, to_os): ], ) def test_generate_plan_in_same_version(status, model, from_to): - app_status = status["keystone-ldap"] + app_status = status["keystone_ldap_focal_ussuri"] app = OpenStackSubordinateApplication( - "my_keystone_ldap", app_status, {}, model, "keystone-ldap" + "my_keystone_ldap", app_status, {}, model, "keystone-ldap", {} ) app.channel = f"{from_to}/stable" diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 15dae6e0..fde2862c 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -13,6 +13,7 @@ # limitations under the License. from collections import OrderedDict +from itertools import zip_longest from pathlib import Path from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch @@ -35,12 +36,53 @@ KEYSTONE_UNITS = ["keystone/0", "keystone/1", "keystone/2"] KEYSTONE_MACHINES = ["0/lxd/12", "1/lxd/12", "2/lxd/13"] KEYSTONE_WORKLOADS = { - "ussuri": ["17.0.1", "17.0.1", "17.0.1"], - "victoria": ["18.1.0", "18.1.0", "18.1.0"], - "ussuri-victoria": ["17.0.1", "17.0.1", "18.1.0"], - "wallaby": ["19.1.0", "19.1.0", "19.1.0"], + "ussuri": "17.0.1", + "victoria": "18.1.0", + "wallaby": "19.1.0", } +CINDER_UNITS = ["cinder/0", "cinder/1", "cinder/2"] +CINDER_MACHINES = ["0/lxd/5", "1/lxd/5", "2/lxd/5"] +CINDER_WORKLOADS = {"ussuri": "16.4.2"} + +NOVA_UNITS = ["nova-compute/0", "nova-compute/1", "nova-compute/2"] +NOVA_MACHINES = ["0", "1", "2"] +NOVA_WORKLOADS = {"ussuri": "21.0.0"} + +RMQ_UNITS = ["rabbitmq-server/0"] +RMQ_MACHINES = ["0/lxd/19"] +RMQ_WORKLOADS = {"3.8": "3.8"} + +CEPH_MON_UNITS = ["ceph-mon/0"] +CEPH_MON_MACHINES = ["6"] + +CEPH_OSD_UNITS = ["ceph-osd/0"] +CEPH_OSD_MACHINES = ["7"] + +CEPH_WORKLOADS = {"octopus": "15.2.0", "pacific": "16.2.0"} + +OVN_UNITS = ["ovn-central/0"] +OVN_MACHINES = ["0/lxd/7"] +OVN_WORKLOADS = {"22.03": "22.03.2", "20.03": "20.03.2"} + +MYSQL_UNITS = ["mysql/0"] +MYSQL_MACHINES = ["0/lxd/7"] +MYSQL_WORKLOADS = {"8.0": "8.0"} + +GLANCE_SIMPLE_UNITS = ["glance-simplestreams-sync/0"] +GLANCE_SIMPLE_MACHINES = ["4/lxd/5"] + +DESIGNATE_UNITS = ["designate-bind/0", "designate-bind/1"] +DESIGNATE_MACHINES = ["1/lxd/6", "2/lxd/6"] +DESIGNATE_WORKLOADS = {"ussuri": "9.16.1"} + +GNOCCHI_UNITS = ["gnocchi/0", "gnocchi/1", "gnocchi/2"] +GNOCCHI_MACHINES = ["3/lxd/6", "4/lxd/6", "5/lxd/5"] +GNOCCHI_WORKLOADS = {"ussuri": "4.3.4", "xena": "4.4.1"} + +MY_APP_UNITS = ["my-app/0"] +MY_APP_MACHINES = ["0/lxd/11"] + def _generate_unit(workload_version, machine): unit = MagicMock(spec_set=UnitStatus()) @@ -63,15 +105,28 @@ def _generate_units(units_machines_workloads): @pytest.fixture def apps_machines(): return { + **_generate_apps_machines("keystone", KEYSTONE_MACHINES, STANDARD_AZS, False), + **_generate_apps_machines("cinder", CINDER_MACHINES, STANDARD_AZS, False), + **_generate_apps_machines("nova-compute", NOVA_MACHINES, STANDARD_AZS, True), + **_generate_apps_machines("rmq", RMQ_MACHINES, STANDARD_AZS, False), + **_generate_apps_machines("ceph-mon", CEPH_MON_MACHINES, STANDARD_AZS, False), + **_generate_apps_machines("ovn-central", OVN_MACHINES, STANDARD_AZS, False), + **_generate_apps_machines("mysql-innodb-cluster", MYSQL_MACHINES, STANDARD_AZS, False), **_generate_apps_machines( - "keystone", KEYSTONE_MACHINES, STANDARD_AZS, [False, False, False] + "glance-simplestreams-sync", GLANCE_SIMPLE_MACHINES, STANDARD_AZS, False ), + **_generate_apps_machines("gnocchi", GNOCCHI_MACHINES, STANDARD_AZS, False), + **_generate_apps_machines("designate-bind", DESIGNATE_MACHINES, STANDARD_AZS, False), + **_generate_apps_machines("ceph-osd", CEPH_OSD_MACHINES, STANDARD_AZS, True), + **_generate_apps_machines("my-app", MY_APP_MACHINES, STANDARD_AZS, False), } def _generate_apps_machines(charm, machines, azs, is_data_plane): hostnames = [f"{HOSTNAME_PREFIX}-{machine}" for machine in machines] - machines_hostnames_azs_is_data_plane = zip(machines, hostnames, azs, is_data_plane) + machines_hostnames_azs_is_data_plane = zip_longest( + machines, hostnames, azs, [is_data_plane], fillvalue=is_data_plane + ) return { charm: { machine_id: Machine( @@ -84,376 +139,334 @@ def _generate_apps_machines(charm, machines, azs, is_data_plane): @pytest.fixture def status(): - # mock_cinder_ussuri = MagicMock(spec_set=ApplicationStatus()) - # mock_cinder_ussuri.series = "focal" - # mock_cinder_ussuri.charm_channel = "ussuri/stable" - # mock_cinder_ussuri.charm = "ch:amd64/focal/cinder-633" - # mock_cinder_ussuri.subordinate_to = [] - # mock_cinder_ussuri.units = OrderedDict( - # [ - # ("cinder/0", generate_unit("cinder", "16.4.2", "0/lxd/5")), - # ("cinder/1", generate_unit("cinder", "16.4.2", "1/lxd/5")), - # ("cinder/2", generate_unit("cinder", "16.4.2", "2/lxd/5")), - # ] - # ) - - # mock_cinder_on_nova = MagicMock(spec_set=ApplicationStatus()) - # mock_cinder_on_nova.series = "focal" - # mock_cinder_on_nova.charm_channel = "ussuri/stable" - # mock_cinder_on_nova.charm = "ch:amd64/focal/cinder-633" - # mock_cinder_on_nova.subordinate_to = [] - # mock_cinder_on_nova.units = OrderedDict( - # [ - # ("cinder/0", generate_unit("cinder-nova", "16.4.2", "0")), - # ("cinder/1", generate_unit("cinder-nova", "16.4.2", "1")), - # ("cinder/2", generate_unit("cinder-nova", "16.4.2", "2")), - # ] - # ) - - # # gnocchi on ussuri - # mock_gnocchi_ussuri = MagicMock(spec_set=ApplicationStatus()) - # mock_gnocchi_ussuri.series = "focal" - # mock_gnocchi_ussuri.charm_channel = "ussuri/stable" - # mock_gnocchi_ussuri.charm = "ch:amd64/focal/gnocchi-638" - # mock_gnocchi_ussuri.subordinate_to = [] - # mock_gnocchi_ussuri.units = OrderedDict( - # [ - # ("gnocchi/0", generate_unit("gnocchi", "4.3.4", "3/lxd/6")), - # ("gnocchi/1", generate_unit("gnocchi", "4.3.4", "4/lxd/6")), - # ("gnocchi/2", generate_unit("gnocchi", "4.3.4", "5/lxd/5")), - # ] - # ) - - # # gnocchi on xena - # mock_gnocchi_xena = MagicMock(spec_set=ApplicationStatus()) - # mock_gnocchi_xena.series = "focal" - # mock_gnocchi_xena.charm_channel = "xena/stable" - # mock_gnocchi_xena.charm = "ch:amd64/focal/gnocchi-638" - # mock_gnocchi_xena.subordinate_to = [] - # mock_gnocchi_xena.units = OrderedDict( - # [ - # ("gnocchi/0", generate_unit("gnocchi", "4.4.1", "3/lxd/6")), - # ("gnocchi/1", generate_unit("gnocchi", "4.4.1", "4/lxd/6")), - # ("gnocchi/2", generate_unit("gnocchi", "4.4.1", "5/lxd/5")), - # ] - # ) - - # # designate-bind on ussuri - # mock_designate_bind_ussuri = MagicMock(spec_set=ApplicationStatus()) - # mock_designate_bind_ussuri.series = "focal" - # mock_designate_bind_ussuri.charm_channel = "ussuri/stable" - # mock_designate_bind_ussuri.charm = "ch:amd64/focal/designate-bind-737" - # mock_designate_bind_ussuri.subordinate_to = [] - # mock_designate_bind_ussuri.units = OrderedDict( - # [ - # ("designate-bind/0", generate_unit("designate-bind", "9.16.1", "1/lxd/6")), - # ("designate-bind/1", generate_unit("designate-bind","9.16.1", "2/lxd/6")), - # ] - # ) - - # mock_nova_ussuri = MagicMock(spec_set=ApplicationStatus()) - # mock_nova_ussuri.series = "focal" - # mock_nova_ussuri.charm_channel = "ussuri/stable" - # mock_nova_ussuri.charm = "ch:amd64/focal/nova-compute-638" - # mock_nova_ussuri.subordinate_to = [] - # mock_nova_ussuri.units = OrderedDict( - # [ - # ("nova-compute/0", generate_unit("nova-compute", "21.0.0", "0")), - # ("nova-compute/1", generate_unit("nova-compute", "21.0.0", "1")), - # ("nova-compute/2", generate_unit("nova-compute", "21.0.0", "2")), - # ] - # ) - - # mock_nova_wallaby = MagicMock(spec_set=ApplicationStatus()) - # mock_nova_wallaby.series = "focal" - # mock_nova_wallaby.charm_channel = "wallaby/stable" - # mock_nova_wallaby.charm = "ch:amd64/focal/nova-compute-638" - # mock_nova_wallaby.subordinate_to = [] - # mock_nova_wallaby.units = OrderedDict( - # [ - # ("nova-compute/0", generate_unit("nova-compute", "24.1.0", "0")), - # ("nova-compute/1", generate_unit("nova-compute", "24.1.0", "1")), - # ("nova-compute/2", generate_unit("nova-compute", "24.1.0", "2")), - # ] - # ) - - # # glance-simplestreams-sync does not have workload_version - # mock_glance_simplestreams_sync_ussuri = MagicMock(spec_set=ApplicationStatus()) - # mock_glance_simplestreams_sync_ussuri.series = "focal" - # mock_glance_simplestreams_sync_ussuri.charm_channel = "ussuri/stable" - # mock_glance_simplestreams_sync_ussuri.charm = "ch:amd64/focal/glance-simplestreams-sync-78" - # mock_glance_simplestreams_sync_ussuri.subordinate_to = [] - # mock_glance_simplestreams_sync_ussuri.units = OrderedDict( - # [ - # ("glance-simplestreams-sync/0", generate_unit("glance-simplestreams-sync", "", "4/lxd/5")), - # ] - # ) - - # mock_rmq = MagicMock(spec_set=ApplicationStatus()) - # mock_rmq.series = "focal" - # mock_rmq.charm_channel = "3.8/stable" - # mock_rmq.charm = "ch:amd64/focal/rabbitmq-server-638" - # mock_rmq.subordinate_to = [] - # mock_rmq.units = OrderedDict([("rabbitmq-server/0", generate_unit("rabbitmq-server", "3.8", "0/lxd/19"))]) - - # mock_rmq_unknown = MagicMock(spec_set=ApplicationStatus()) - # mock_rmq_unknown.series = "focal" - # mock_rmq_unknown.charm_channel = "80.5/stable" - # mock_rmq_unknown.charm = "ch:amd64/focal/rabbitmq-server-638" - # mock_rmq_unknown.subordinate_to = [] - # mock_rmq_unknown.units = OrderedDict( - # [("rabbitmq-server/0", generate_unit("rabbitmq-server", "80.5", "0/lxd/19"))] - # ) - - # mock_unknown_app = MagicMock(spec_set=ApplicationStatus()) - # mock_unknown_app.series = "focal" - # mock_unknown_app.charm_channel = "12.5/stable" - # mock_unknown_app.charm = "ch:amd64/focal/my-app-638" - # mock_unknown_app.subordinate_to = [] - # mock_unknown_app.units = OrderedDict([("my-app/0", generate_unit("my-app", "12.5", "0/lxd/11"))]) - - # # openstack related principal application without openstack origin or source - # mock_vault = MagicMock(spec_set=ApplicationStatus()) - # mock_vault.series = "focal" - # mock_vault.charm_channel = "1.7/stable" - # mock_vault.charm = "ch:amd64/focal/vault-638" - # mock_vault.subordinate_to = [] - # mock_vault.units = OrderedDict([("vault/0", generate_unit("vault", "1.7", "5"))]) - - # # auxiliary subordinate application - # mock_mysql_router = MagicMock(spec_set=ApplicationStatus()) - # mock_mysql_router.series = "focal" - # mock_mysql_router.charm_channel = "8.0/stable" - # mock_mysql_router.charm = "ch:amd64/focal/mysql-router-437" - # mock_mysql_router.subordinate_to = ["keystone"] - # mock_mysql_router.units = {} - - # # OpenStack subordinate application - # mock_keystone_ldap = MagicMock(spec_set=ApplicationStatus()) - # mock_keystone_ldap.series = "focal" - # mock_keystone_ldap.charm_channel = "ussuri/stable" - # mock_keystone_ldap.charm = "ch:amd64/focal/keystone-ldap-437" - # mock_keystone_ldap.subordinate_to = ["keystone"] - # mock_keystone_ldap.units = {} - - # # OpenStack subordinate application cs - # mock_keystone_ldap_cs = MagicMock(spec_set=ApplicationStatus()) - # mock_keystone_ldap_cs.series = "focal" - # mock_keystone_ldap_cs.charm_channel = "stable" - # mock_keystone_ldap_cs.charm = "cs:amd64/focal/keystone-ldap-437" - # mock_keystone_ldap_cs.subordinate_to = ["keystone"] - # mock_keystone_ldap_cs.units = {} - - # # ceph-mon application on ussuri - # mock_ceph_mon_ussuri = MagicMock(spec_set=ApplicationStatus()) - # mock_ceph_mon_ussuri.series = "focal" - # mock_ceph_mon_ussuri.charm_channel = "octopus/stable" - # mock_ceph_mon_ussuri.charm = "ch:amd64/focal/ceph-mon-177" - # mock_ceph_mon_ussuri.subordinate_to = [] - # mock_ceph_mon_ussuri.units = OrderedDict([("ceph-mon/0", generate_unit("ceph-mon", "15.2.0", "6"))]) - - # # ceph-mon application on xena - # mock_ceph_mon_xena = MagicMock(spec_set=ApplicationStatus()) - # mock_ceph_mon_xena.series = "focal" - # mock_ceph_mon_xena.charm_channel = "pacific/stable" - # mock_ceph_mon_xena.charm = "ch:amd64/focal/ceph-mon-178" - # mock_ceph_mon_xena.subordinate_to = [] - # mock_ceph_mon_xena.units = OrderedDict([("ceph-mon/0", generate_unit("ceph-mon", "16.2.0", "7"))]) - - # # ceph-osd application on ussuri - # mock_ceph_osd_ussuri = MagicMock(spec_set=ApplicationStatus()) - # mock_ceph_osd_ussuri.series = "focal" - # mock_ceph_osd_ussuri.charm_channel = "octopus/stable" - # mock_ceph_osd_ussuri.charm = "ch:amd64/focal/ceph-osd-177" - # mock_ceph_osd_ussuri.subordinate_to = [] - # mock_ceph_osd_ussuri.units = OrderedDict([("ceph-osd/0", generate_unit("ceph-mon", "15.2.0", "6"))]) - - # # mysql-innodb-cluster application on ussuri using 8.0 - # mock_mysql_innodb_cluster_ussuri = MagicMock(spec_set=ApplicationStatus()) - # mock_mysql_innodb_cluster_ussuri.series = "focal" - # mock_mysql_innodb_cluster_ussuri.charm_channel = "8.0/stable" - # mock_mysql_innodb_cluster_ussuri.charm = "ch:amd64/focal/mysql-innodb-cluster-106" - # mock_mysql_innodb_cluster_ussuri.subordinate_to = [] - # mock_mysql_innodb_cluster_ussuri.units = OrderedDict( - # [("ovn-central/0", generate_unit("ovn-central", "8.0", "0/lxd/7"))] - # ) - - # # ovn-central application on ussuri using 22.03 - # mock_ovn_central_ussuri_22 = MagicMock(spec_set=ApplicationStatus()) - # mock_ovn_central_ussuri_22.series = "focal" - # mock_ovn_central_ussuri_22.charm_channel = "22.03/stable" - # mock_ovn_central_ussuri_22.charm = "ch:amd64/focal/ovn-central-178" - # mock_ovn_central_ussuri_22.subordinate_to = [] - # mock_ovn_central_ussuri_22.units = OrderedDict( - # [("ovn-central/0", generate_unit("ovn-central", "22.03.2", "0/lxd/7"))] - # ) - - # # ovn-central application on ussuri using 20.03 - # mock_ovn_central_ussuri_20 = MagicMock(spec_set=ApplicationStatus()) - # mock_ovn_central_ussuri_20.series = "focal" - # mock_ovn_central_ussuri_20.charm_channel = "20.03/stable" - # mock_ovn_central_ussuri_20.charm = "ch:amd64/focal/ovn-central-178" - # mock_ovn_central_ussuri_20.subordinate_to = [] - # mock_ovn_central_ussuri_20.units = OrderedDict( - # [("ovn-central/0", generate_unit("ovn-central", "20.03.2", "0/lxd/7"))] - # ) - - # # ovn-chassis application on ussuri using 22.03 - # mock_ovn_chassis_ussuri_22 = MagicMock(spec_set=ApplicationStatus()) - # mock_ovn_chassis_ussuri_22.series = "focal" - # mock_ovn_chassis_ussuri_22.charm_channel = "22.03/stable" - # mock_ovn_chassis_ussuri_22.charm = "ch:amd64/focal/ovn-chassis-178" - # mock_ovn_chassis_ussuri_22.workload_version = "22.03.2" - # mock_ovn_chassis_ussuri_22.subordinate_to = ["nova-compute"] - # mock_ovn_chassis_ussuri_22.units = {} - - # # ovn-chassis application on ussuri using 20.03 - # mock_ovn_chassis_ussuri_20 = MagicMock(spec_set=ApplicationStatus()) - # mock_ovn_chassis_ussuri_20.series = "focal" - # mock_ovn_chassis_ussuri_20.charm_channel = "20.03/stable" - # mock_ovn_chassis_ussuri_20.charm = "ch:amd64/focal/ovn-chassis-178" - # mock_ovn_chassis_ussuri_20.subordinate_to = ["nova-compute"] - # mock_ovn_chassis_ussuri_20.workload_version = "20.03.2" - # mock_ovn_chassis_ussuri_20.units = {} - - # # ceph-dashboard on ussuri - # mock_ceph_dashboard_ussuri = MagicMock(spec_set=ApplicationStatus()) - # mock_ceph_dashboard_ussuri.series = "focal" - # mock_ceph_dashboard_ussuri.charm_channel = "octopus/stable" - # mock_ceph_dashboard_ussuri.charm = "ch:amd64/focal/ceph-dashboard-178" - # mock_ceph_dashboard_ussuri.subordinate_to = ["ceph-mon"] - # mock_ceph_dashboard_ussuri.units = {} - - # # ceph-dashboard on xena - # mock_ceph_dashboard_xena = MagicMock(spec_set=ApplicationStatus()) - # mock_ceph_dashboard_xena.series = "focal" - # mock_ceph_dashboard_xena.charm_channel = "pacific/stable" - # mock_ceph_dashboard_xena.charm = "ch:amd64/focal/ceph-dashboard-178" - # mock_ceph_dashboard_xena.subordinate_to = ["ceph-mon"] - # mock_ceph_dashboard_xena.units = {} - - status = { - **generate_keystone_status() - # "cinder_ussuri": mock_cinder_ussuri, - # "glance_simplestreams_sync_ussuri": mock_glance_simplestreams_sync_ussuri, - # "gnocchi_ussuri": mock_gnocchi_ussuri, - # "gnocchi_xena": mock_gnocchi_xena, - # "designate_bind_ussuri": mock_designate_bind_ussuri, - # "rabbitmq_server": mock_rmq, - # "unknown_rabbitmq_server": mock_rmq_unknown, - # "unknown_app": mock_unknown_app, - # "mysql_router": mock_mysql_router, - # "vault": mock_vault, - # "keystone-ldap": mock_keystone_ldap, - # "keystone-ldap-cs": mock_keystone_ldap_cs, - # "nova_ussuri": mock_nova_ussuri, - # "nova_wallaby": mock_nova_wallaby, - # "ceph-mon_ussuri": mock_ceph_mon_ussuri, - # "ceph-mon_xena": mock_ceph_mon_xena, - # "ceph_osd_ussuri": mock_ceph_osd_ussuri, - # "ceph_dashboard_ussuri": mock_ceph_dashboard_ussuri, - # "ceph_dashboard_xena": mock_ceph_dashboard_xena, - # "cinder_ussuri_on_nova": mock_cinder_on_nova, - # "mysql-innodb-cluster": mock_mysql_innodb_cluster_ussuri, - # "ovn_central_ussuri_22": mock_ovn_central_ussuri_22, - # "ovn_central_ussuri_20": mock_ovn_central_ussuri_20, - # "ovn_chassis_ussuri_22": mock_ovn_chassis_ussuri_22, - # "ovn_chassis_ussuri_20": mock_ovn_chassis_ussuri_20, + return { + **generate_keystone_status(), + **generate_cinder_status(), + **generate_nova_status(), + **generate_rmq_status(), + **generate_ceph_mon_status(), + **generate_ceph_osd_status(), + **generate_ovn_central_status(), + **generate_mysql_innodb_cluster_status(), + **generate_glance_simplestreams_sync_status(), + **generate_gnocchi_status(), + **generate_ovn_chassis_status(), + **generate_ceph_dashboard_status(), + **generate_keystone_ldap_status(), + **generate_designate_bind_status(), + **generate_mysql_router_status(), + **generate_my_app(), } - return status def generate_keystone_status(): - keystone_units = ["keystone/0", "keystone/1", "keystone/2"] - keystone_machines = ["0/lxd/12", "1/lxd/12", "2/lxd/13"] - - keystone_workloads = { - "ussuri": ["17.0.1", "17.0.1", "17.0.1"], - "victoria": ["18.1.0", "18.1.0", "18.1.0"], - "ussuri-victoria": ["17.0.1", "17.0.1", "18.1.0"], - "wallaby": ["19.1.0", "19.1.0", "19.1.0"], - } - mock_keystone_focal_ussuri = _generate_status( "focal", "ussuri/stable", "ch:amd64/focal/keystone-638", [], - keystone_units, - keystone_machines, - keystone_workloads["ussuri"], + KEYSTONE_UNITS, + KEYSTONE_MACHINES, + KEYSTONE_WORKLOADS["ussuri"], + ) + + mock_keystone_focal_victoria = _generate_status( + "focal", + "wallaby/stable", + "ch:amd64/focal/keystone-638", + [], + KEYSTONE_UNITS, + KEYSTONE_MACHINES, + KEYSTONE_WORKLOADS["victoria"], ) - mock_keystone_bionic_ussuri = _generate_status( - "bionic", + mock_keystone_focal_wallaby = _generate_status( + "focal", + "wallaby/stable", + "ch:amd64/focal/keystone-638", + [], + KEYSTONE_UNITS, + KEYSTONE_MACHINES, + KEYSTONE_WORKLOADS["wallaby"], + ) + + return { + "keystone_focal_ussuri": mock_keystone_focal_ussuri, + "keystone_focal_victoria": mock_keystone_focal_victoria, + "keystone_focal_wallaby": mock_keystone_focal_wallaby, + } + + +def generate_cinder_status(): + mock_cinder_focal_ussuri = _generate_status( + "focal", "ussuri/stable", - "ch:amd64/bionic/keystone-638", + "ch:amd64/focal/cinder-633", [], - keystone_units, - keystone_machines, - keystone_workloads["ussuri"], + CINDER_UNITS, + CINDER_MACHINES, + CINDER_WORKLOADS["ussuri"], ) + return {"cinder_focal_ussuri": mock_cinder_focal_ussuri} + - mock_keystone_focal_ussuri_cs = _generate_status( +def generate_nova_status(): + mock_nova_focal_ussuri = _generate_status( "focal", "ussuri/stable", - "cs:amd64/focal/keystone-638", + "ch:amd64/focal/nova-compute-638", [], - keystone_units, - keystone_machines, - keystone_workloads["ussuri"], + NOVA_UNITS, + NOVA_MACHINES, + NOVA_WORKLOADS["ussuri"], ) + return {"nova_focal_ussuri": mock_nova_focal_ussuri} - mock_keystone_focal_victoria = _generate_status( + +def generate_rmq_status(): + mock_rmq = _generate_status( "focal", - "wallaby/stable", - "ch:amd64/focal/keystone-638", + "3.8/stable", + "ch:amd64/focal/rabbitmq-server-638", [], - keystone_units, - keystone_machines, - keystone_workloads["victoria"], + RMQ_UNITS, + RMQ_MACHINES, + RMQ_WORKLOADS["3.8"], ) + mock_rmq_unknown = _generate_status( + "focal", + "80.5/stable", + "ch:amd64/focal/rabbitmq-server-638", + [], + RMQ_UNITS, + RMQ_MACHINES, + "80.5", + ) + + return {"rabbitmq_server": mock_rmq, "unknown_rabbitmq_server": mock_rmq_unknown} - mock_keystone_focal_ussuri_victoria = _generate_status( + +def generate_ceph_mon_status(): + mock_ceph_mon_octopus = _generate_status( "focal", - "victoria/stable", - "ch:amd64/focal/keystone-638", + "octopus/stable", + "ch:amd64/focal/ceph-mon-178", + [], + CEPH_MON_UNITS, + CEPH_MON_MACHINES, + CEPH_WORKLOADS["octopus"], + ) + mock_ceph_mon_pacific = _generate_status( + "focal", + "pacific/stable", + "ch:amd64/focal/ceph-mon-178", [], - keystone_units, - keystone_machines, - keystone_workloads["ussuri-victoria"], + CEPH_MON_UNITS, + CEPH_MON_MACHINES, + CEPH_WORKLOADS["pacific"], ) + return {"ceph_mon_octopus": mock_ceph_mon_octopus, "ceph_mon_pacific": mock_ceph_mon_pacific} - mock_keystone_focal_wallaby = _generate_status( + +def generate_ceph_osd_status(): + mock_ceph_osd_octopus = _generate_status( "focal", - "wallaby/stable", - "ch:amd64/focal/keystone-638", + "octopus/stable", + "ch:amd64/focal/ceph-osd-177", [], - keystone_units, - keystone_machines, - keystone_workloads["wallaby"], + CEPH_OSD_UNITS, + CEPH_OSD_MACHINES, + CEPH_WORKLOADS["octopus"], ) + return {"ceph_osd_octopus": mock_ceph_osd_octopus} + +def generate_ovn_central_status(): + mock_ovn_central_20 = _generate_status( + "focal", + "20.03/stable", + "ch:amd64/focal/ovn-central-178", + [], + OVN_UNITS, + OVN_MACHINES, + OVN_WORKLOADS["20.03"], + ) + mock_ovn_central_22 = _generate_status( + "focal", + "22.03/stable", + "ch:amd64/focal/ovn-central-178", + [], + OVN_UNITS, + OVN_MACHINES, + OVN_WORKLOADS["22.03"], + ) + return {"ovn_central_20": mock_ovn_central_20, "ovn_central_22": mock_ovn_central_22} + + +def generate_mysql_innodb_cluster_status(): + mock_mysql_innodb_cluster = _generate_status( + "focal", + "8.0/stable", + "ch:amd64/focal/mysql-innodb-cluster-106", + [], + MYSQL_UNITS, + MYSQL_MACHINES, + MYSQL_WORKLOADS["8.0"], + ) + return {"mysql_innodb_cluster": mock_mysql_innodb_cluster} + + +def generate_glance_simplestreams_sync_status(): + mock_glance_simplestreams_sync_focal_ussuri = _generate_status( + "focal", + "ussuri/stable", + "ch:amd64/focal/glance-simplestreams-sync-78", + [], + GLANCE_SIMPLE_UNITS, + GLANCE_SIMPLE_MACHINES, + "", # there is no workload version for glance-simplestreams-sync + ) + return {"glance_simplestreams_sync_focal_ussuri": mock_glance_simplestreams_sync_focal_ussuri} + + +def generate_designate_bind_status(): + mock_designate_bind_focal_ussuri = _generate_status( + "focal", + "ussuri/stable", + "ch:amd64/focal/designate-bind-737", + [], + DESIGNATE_UNITS, + DESIGNATE_MACHINES, + DESIGNATE_WORKLOADS["ussuri"], + ) return { - "keystone_focal_ussuri": mock_keystone_focal_ussuri, - "keystone_bionic_ussuri": mock_keystone_bionic_ussuri, - "keystone_focal_ussuri_cs": mock_keystone_focal_ussuri_cs, - "keystone_focal_ussuri_victoria": mock_keystone_focal_ussuri_victoria, - "keystone_focal_victoria": mock_keystone_focal_victoria, - "keystone_focal_wallaby": mock_keystone_focal_wallaby, + "designate_bind_focal_ussuri": mock_designate_bind_focal_ussuri, + } + + +def generate_gnocchi_status(): + mock_gnocchi_focal_ussuri = _generate_status( + "focal", + "ussuri/stable", + "ch:amd64/focal/gnocchi-638", + [], + GNOCCHI_UNITS, + GNOCCHI_MACHINES, + GNOCCHI_WORKLOADS["ussuri"], + ) + mock_gnocchi_focal_xena = _generate_status( + "focal", + "xena/stable", + "ch:amd64/focal/gnocchi-638", + [], + GNOCCHI_UNITS, + GNOCCHI_MACHINES, + GNOCCHI_WORKLOADS["xena"], + ) + return { + "gnocchi_focal_ussuri": mock_gnocchi_focal_ussuri, + "gnocchi_focal_xena": mock_gnocchi_focal_xena, } +def generate_ovn_chassis_status(): + mock_ovn_chassis_focal_22 = _generate_status( + "focal", + "22.03/stable", + "ch:amd64/focal/ovn-chassis-178", + ["nova-compute"], + [], + [], + OVN_WORKLOADS["22.03"], + ) + mock_ovn_chassis_focal_20 = _generate_status( + "focal", + "20.03/stable", + "ch:amd64/focal/ovn-chassis-178", + ["nova-compute"], + [], + [], + OVN_WORKLOADS["20.03"], + ) + return { + "ovn_chassis_focal_20": mock_ovn_chassis_focal_20, + "ovn_chassis_focal_22": mock_ovn_chassis_focal_22, + } + + +def generate_keystone_ldap_status(): + mock_keystone_ldap_focal_ussuri = _generate_status( + "focal", + "ussuri/stable", + "ch:amd64/focal/keystone-ldap-437", + ["keystone"], + [], + [], + "", + ) + return {"keystone_ldap_focal_ussuri": mock_keystone_ldap_focal_ussuri} + + +def generate_ceph_dashboard_status(): + mock_ceph_dashboard_octopus = _generate_status( + "focal", + "octopus/stable", + "ch:amd64/focal/ceph-dashboard-178", + ["ceph-mon"], + [], + [], + CEPH_WORKLOADS["octopus"], + ) + mock_ceph_dashboard_pacific = _generate_status( + "focal", + "pacific/stable", + "ch:amd64/focal/ceph-dashboard-178", + ["ceph-mon"], + [], + [], + CEPH_WORKLOADS["pacific"], + ) + return { + "ceph_dashboard_octopus": mock_ceph_dashboard_octopus, + "ceph_dashboard_pacific": mock_ceph_dashboard_pacific, + } + + +def generate_mysql_router_status(): + mock_mysql_router = _generate_status( + "focal", "8.0/stable", "ch:amd64/focal/mysql-router-437", ["keystone"], [], [], "" + ) + return {"mysql_router": mock_mysql_router} + + +def generate_my_app(): + mock_my_app = _generate_status( + "focal", + "12.5/stable", + "ch:amd64/focal/my-app-638", + [], + ["my-app/0"], + ["0/lxd/11"], + "12.5", + ) + return {"my_app": mock_my_app} + + def _generate_status( - series, charm_channel, charm, subordinate_to, units, machines, workload_versions + series, charm_channel, charm, subordinate_to, units, machines, workload_version ): app_mock = MagicMock(spec_set=ApplicationStatus()) app_mock.series = series app_mock.charm_channel = charm_channel app_mock.charm = charm app_mock.subordinate_to = subordinate_to + # subordinates get workload version from the application + if subordinate_to: + app_mock.workload_version = workload_version - units_machines_workloads = zip(units, machines, workload_versions) + units_machines_workloads = zip_longest( + units, machines, [workload_version], fillvalue=workload_version + ) app_mock.units = _generate_units(units_machines_workloads) return app_mock @@ -464,12 +477,12 @@ def full_status(status, model): mock_full_status.model.name = model.name mock_full_status.applications = OrderedDict( [ - ("keystone", status["keystone_ussuri"]), - ("cinder", status["cinder_ussuri"]), + ("keystone", status["keystone_focal_ussuri"]), + ("cinder", status["cinder_focal_ussuri"]), ("rabbitmq-server", status["rabbitmq_server"]), - ("my_app", status["unknown_app"]), - ("nova-compute", status["nova_ussuri"]), - ("ceph-osd", status["ceph_osd_ussuri"]), + ("my_app", status["my_app"]), + ("nova-compute", status["nova_focal_ussuri"]), + ("ceph-osd", status["ceph_osd_octopus"]), ] ) return mock_full_status @@ -584,50 +597,76 @@ def model(config, apps_machines): @pytest.fixture -def apps(status, config, model): - keystone_ussuri_status = status["keystone_ussuri"] - keystone_wallaby_status = status["keystone_wallaby"] - cinder_ussuri_status = status["cinder_ussuri"] +def apps(status, config, model, apps_machines): + keystone_focal_ussuri_status = status["keystone_focal_ussuri"] + keystone_focal_wallaby_status = status["keystone_focal_wallaby"] + cinder_focal_ussuri_status = status["cinder_focal_ussuri"] rmq_status = status["rabbitmq_server"] - keystone_ldap_status = status["keystone-ldap"] - keystone_bionic_ussuri_status = status["keystone_bionic_ussuri"] + keystone_ldap_focal_ussuri_status = status["keystone_ldap_focal_ussuri"] keystone_ussuri = Keystone( - "keystone", keystone_ussuri_status, config["openstack_ussuri"], model, "keystone" + "keystone", + keystone_focal_ussuri_status, + config["openstack_ussuri"], + model, + "keystone", + apps_machines["keystone"], ) keystone_wallaby = Keystone( - "keystone", keystone_wallaby_status, config["openstack_wallaby"], model, "keystone" - ) - keystone_bionic_ussuri = OpenStackApplication( - "keystone", keystone_bionic_ussuri_status, config["openstack_ussuri"], model, "keystone" + "keystone", + keystone_focal_wallaby_status, + config["openstack_wallaby"], + model, + "keystone", + apps_machines["keystone"], ) cinder_ussuri = OpenStackApplication( - "cinder", cinder_ussuri_status, config["openstack_ussuri"], model, "cinder" + "cinder", + cinder_focal_ussuri_status, + config["openstack_ussuri"], + model, + "cinder", + apps_machines["cinder"], ) - rmq_ussuri = OpenStackAuxiliaryApplication( - "rabbitmq-server", rmq_status, config["auxiliary_ussuri"], model, "rabbitmq-server" + rmq = OpenStackAuxiliaryApplication( + "rabbitmq-server", + rmq_status, + config["auxiliary_ussuri"], + model, + "rabbitmq-server", + apps_machines["rmq"], ) rmq_wallaby = OpenStackAuxiliaryApplication( - "rabbitmq-server", rmq_status, config["auxiliary_wallaby"], model, "rabbitmq-server" + "rabbitmq-server", + rmq_status, + config["auxiliary_wallaby"], + model, + "rabbitmq-server", + apps_machines["rmq"], ) keystone_ldap = OpenStackSubordinateApplication( - "keystone-ldap", keystone_ldap_status, {}, model, "keystone-ldap" + "keystone-ldap", keystone_ldap_focal_ussuri_status, {}, model, "keystone-ldap", {} ) keystone_mysql_router = OpenStackAuxiliarySubordinateApplication( - "keystone-mysql-router", status["mysql_router"], {}, model, "mysql-router" + "keystone-mysql-router", status["mysql_router"], {}, model, "mysql-router", {} ) - nova_ussuri = OpenStackApplication( - "nova-compute", status["nova_ussuri"], config["openstack_ussuri"], model, "nova-compute" + nova_focal_ussuri = OpenStackApplication( + "nova-compute", + status["nova_focal_ussuri"], + config["openstack_ussuri"], + model, + "nova-compute", + apps_machines["nova-compute"], + apps_machines["nova-compute"], ) return { - "keystone_ussuri": keystone_ussuri, - "keystone_wallaby": keystone_wallaby, - "keystone_bionic_ussuri": keystone_bionic_ussuri, - "cinder_ussuri": cinder_ussuri, - "rmq_ussuri": rmq_ussuri, + "keystone_focal_ussuri": keystone_ussuri, + "keystone_focal_wallaby": keystone_wallaby, + "cinder_focal_ussuri": cinder_ussuri, + "rmq": rmq, "rmq_wallaby": rmq_wallaby, - "keystone_ldap": keystone_ldap, - "nova_ussuri": nova_ussuri, + "keystone_ldap_focal_ussuri": keystone_ldap, + "nova_focal_ussuri": nova_focal_ussuri, "keystone_mysql_router": keystone_mysql_router, } diff --git a/tests/unit/steps/test_steps_analyze.py b/tests/unit/steps/test_steps_analyze.py index 97c25e5c..d03530da 100644 --- a/tests/unit/steps/test_steps_analyze.py +++ b/tests/unit/steps/test_steps_analyze.py @@ -16,6 +16,7 @@ import pytest from cou.apps.base import ApplicationUnit, OpenStackApplication +from cou.apps.machine import Machine from cou.steps import analyze from cou.steps.analyze import Analysis @@ -75,9 +76,9 @@ def test_analysis_dump(apps, model): result = analyze.Analysis( model=model, apps_control_plane=[ - apps["keystone_ussuri"], - apps["cinder_ussuri"], - apps["rmq_ussuri"], + apps["keystone_focal_ussuri"], + apps["cinder_focal_ussuri"], + apps["rmq"], ], apps_data_plane=[], ) @@ -85,10 +86,16 @@ def test_analysis_dump(apps, model): @pytest.mark.asyncio -async def test_populate_model(full_status, config, model): +async def test_populate_model(full_status, config, model, apps_machines): model.get_status = AsyncMock(return_value=full_status) model.get_application_config = AsyncMock(return_value=config["openstack_ussuri"]) + machines = {} + for sub_dict in apps_machines.values(): + machines.update(sub_dict) + + model.get_model_machines = AsyncMock(return_value=machines) + # Initially, 6 applications are in the status: keystone, cinder, rabbitmq-server, my-app, # ceph-osd and nova-compute. my-app it's not on the lookup table, so won't be instantiated. assert len(full_status.applications) == 6 @@ -108,7 +115,7 @@ async def test_populate_model(full_status, config, model): @patch.object(analyze.Analysis, "_populate", new_callable=AsyncMock) async def test_analysis_create(mock_populate, apps, model): """Test analysis object.""" - exp_apps = [apps["keystone_ussuri"], apps["cinder_ussuri"], apps["rmq_ussuri"]] + exp_apps = [apps["keystone_focal_ussuri"], apps["cinder_focal_ussuri"], apps["rmq"]] expected_result = analyze.Analysis( model=model, apps_control_plane=exp_apps, apps_data_plane=[] ) @@ -123,7 +130,11 @@ async def test_analysis_create(mock_populate, apps, model): async def test_analysis_detect_current_cloud_os_release_different_releases(apps, model): result = analyze.Analysis( model=model, - apps_control_plane=[apps["rmq_ussuri"], apps["keystone_wallaby"], apps["cinder_ussuri"]], + apps_control_plane=[ + apps["rmq"], + apps["keystone_focal_wallaby"], + apps["cinder_focal_ussuri"], + ], apps_data_plane=[], ) @@ -135,7 +146,7 @@ async def test_analysis_detect_current_cloud_os_release_different_releases(apps, async def test_analysis_detect_current_cloud_os_release_same_release(apps, model): result = analyze.Analysis( model=model, - apps_control_plane=[apps["cinder_ussuri"], apps["keystone_ussuri"]], + apps_control_plane=[apps["cinder_focal_ussuri"], apps["keystone_focal_ussuri"]], apps_data_plane=[], ) @@ -147,7 +158,11 @@ async def test_analysis_detect_current_cloud_os_release_same_release(apps, model async def test_analysis_detect_current_cloud_series_same_series(apps, model): result = analyze.Analysis( model=model, - apps_control_plane=[apps["rmq_ussuri"], apps["keystone_wallaby"], apps["cinder_ussuri"]], + apps_control_plane=[ + apps["rmq"], + apps["keystone_focal_wallaby"], + apps["cinder_focal_ussuri"], + ], apps_data_plane=[], ) @@ -157,9 +172,13 @@ async def test_analysis_detect_current_cloud_series_same_series(apps, model): @pytest.mark.asyncio async def test_analysis_detect_current_cloud_series_different_series(apps, model): + # change keystone to bionic + keystone_bionic_ussuri = apps["keystone_focal_ussuri"] + keystone_bionic_ussuri.status.series = "bionic" + result = analyze.Analysis( model=model, - apps_control_plane=[apps["cinder_ussuri"], apps["keystone_bionic_ussuri"]], + apps_control_plane=[apps["cinder_focal_ussuri"], keystone_bionic_ussuri], apps_data_plane=[], ) @@ -174,9 +193,12 @@ def _app(name, units): return app -def _unit(machine): +def _unit(machine_id, is_data_plane): unit = MagicMock(spec_set=ApplicationUnit).return_value - unit.machine = machine + mock_machine = MagicMock(spec_set=Machine("1", "juju-efc45", "zone-1", False)) + mock_machine.machine_id = machine_id + mock_machine.is_data_plane = is_data_plane + unit.machine = mock_machine return unit @@ -184,22 +206,22 @@ def _unit(machine): "exp_control_plane, exp_data_plane", [ ( - [_app("keystone", [_unit("0"), _unit("1"), _unit("2")])], - [_app("ceph-osd", [_unit("3"), _unit("4"), _unit("5")])], + [_app("keystone", [_unit("0", False), _unit("1", False), _unit("2", False)])], + [_app("ceph-osd", [_unit("3", True), _unit("4", True), _unit("5", True)])], ), ( [], [ - _app("nova-compute", [_unit("0"), _unit("1"), _unit("2")]), - _app("keystone", [_unit("0"), _unit("1"), _unit("2")]), - _app("ceph-osd", [_unit("3"), _unit("4"), _unit("5")]), + _app("nova-compute", [_unit("0", True), _unit("1", True), _unit("2", True)]), + _app("keystone", [_unit("0", False), _unit("1", False), _unit("2", False)]), + _app("ceph-osd", [_unit("3", True), _unit("4", True), _unit("5", True)]), ], ), ( - [_app("keystone", [_unit("6"), _unit("7"), _unit("8")])], + [_app("keystone", [_unit("6", False), _unit("7", False), _unit("8", False)])], [ - _app("nova-compute", [_unit("0"), _unit("1"), _unit("2")]), - _app("ceph-osd", [_unit("3"), _unit("4"), _unit("5")]), + _app("nova-compute", [_unit("0", True), _unit("1", True), _unit("2", True)]), + _app("ceph-osd", [_unit("3", True), _unit("4", True), _unit("5", True)]), ], ), ], diff --git a/tests/unit/steps/test_steps_plan.py b/tests/unit/steps/test_steps_plan.py index 360dc73a..4850d1bb 100644 --- a/tests/unit/steps/test_steps_plan.py +++ b/tests/unit/steps/test_steps_plan.py @@ -133,9 +133,9 @@ def generate_expected_upgrade_plan_subordinate(app, target, model): @pytest.mark.asyncio async def test_generate_plan(apps, model, cli_args): target = OpenStackRelease("victoria") - app_keystone = apps["keystone_ussuri"] - app_cinder = apps["cinder_ussuri"] - app_keystone_ldap = apps["keystone_ldap"] + app_keystone = apps["keystone_focal_ussuri"] + app_cinder = apps["cinder_focal_ussuri"] + app_keystone_ldap = apps["keystone_ldap_focal_ussuri"] analysis_result = Analysis( model=model, apps_control_plane=[app_keystone, app_cinder, app_keystone_ldap], @@ -296,8 +296,8 @@ async def test_create_upgrade_plan_failed(): def test_plan_print_warn_manually_upgrade(mock_print, model, apps): result = Analysis( model=model, - apps_control_plane=[apps["keystone_wallaby"]], - apps_data_plane=[apps["nova_ussuri"]], + apps_control_plane=[apps["keystone_focal_wallaby"]], + apps_data_plane=[apps["nova_focal_ussuri"]], ) manually_upgrade_data_plane(result) mock_print.assert_called_with( @@ -309,8 +309,8 @@ def test_plan_print_warn_manually_upgrade(mock_print, model, apps): def test_analysis_not_print_warn_manually_upgrade(mock_print, model, apps): result = Analysis( model=model, - apps_control_plane=[apps["keystone_ussuri"]], - apps_data_plane=[apps["nova_ussuri"]], + apps_control_plane=[apps["keystone_focal_ussuri"]], + apps_data_plane=[apps["nova_focal_ussuri"]], ) manually_upgrade_data_plane(result) mock_print.assert_not_called()