From e8c0ca9717e96b78800c017bac3ad1506123c6c1 Mon Sep 17 00:00:00 2001 From: Dmitry Ratushnyy Date: Thu, 4 Jan 2024 15:59:19 +0000 Subject: [PATCH] Charm integration --- tests/integration/test_charm.py | 60 ++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/tests/integration/test_charm.py b/tests/integration/test_charm.py index a3c6cd250..bd3dbaac4 100644 --- a/tests/integration/test_charm.py +++ b/tests/integration/test_charm.py @@ -15,13 +15,14 @@ from pytest_operator.plugin import OpsTest from tenacity import RetryError -from .ha_tests.helpers import app_name, kill_unit_process +from .ha_tests.helpers import kill_unit_process from .helpers import ( - APP_NAME, PORT, UNIT_IDS, + check_or_scale_app, count_primaries, find_unit, + get_app_name, get_leader_id, get_password, set_password, @@ -30,7 +31,6 @@ logger = logging.getLogger(__name__) -ANOTHER_DATABASE_APP_NAME = "another-database-a" MEDIAN_REELECTION_TIME = 12 @@ -42,6 +42,12 @@ @pytest.mark.abort_on_fail async def test_build_and_deploy(ops_test: OpsTest) -> None: """Build and deploy one unit of MongoDB.""" + # it is possible for users to provide their own cluster for testing. Hence check if there + # is a pre-existing cluster. + app_name = await get_app_name(ops_test) + if app_name: + return check_or_scale_app(ops_test, app_name, len(UNIT_IDS)) + my_charm = await ops_test.build_charm(".") await ops_test.model.deploy(my_charm, num_units=len(UNIT_IDS)) await ops_test.model.wait_for_idle() @@ -50,17 +56,19 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: @pytest.mark.abort_on_fail async def test_status(ops_test: OpsTest) -> None: """Verifies that the application and unit are active.""" - await ops_test.model.wait_for_idle(apps=[APP_NAME], status="active", timeout=1000) - assert len(ops_test.model.applications[APP_NAME].units) == len(UNIT_IDS) + app_name = await get_app_name(ops_test) + await ops_test.model.wait_for_idle(apps=[app_name], status="active", timeout=1000) + assert len(ops_test.model.applications[app_name].units) == len(UNIT_IDS) @pytest.mark.parametrize("unit_id", UNIT_IDS) async def test_unit_is_running_as_replica_set(ops_test: OpsTest, unit_id: int) -> None: """Tests that mongodb is running as a replica set for the application unit.""" # connect to mongo replica set - unit = ops_test.model.applications[APP_NAME].units[unit_id] + app_name = await get_app_name(ops_test) + unit = ops_test.model.applications[app_name].units[unit_id] connection = unit.public_address + ":" + str(PORT) - client = MongoClient(connection, replicaset="mongodb") + client = MongoClient(connection, replicaset=app_name) # check mongo replica set is ready try: @@ -82,7 +90,10 @@ async def test_leader_is_primary_on_deployment(ops_test: OpsTest) -> None: # connect to mongod password = await get_password(ops_test) - client = MongoClient(unit_uri(leader_unit.public_address, password), directConnection=True) + user_app_name = await get_app_name(ops_test) + client = MongoClient( + unit_uri(leader_unit.public_address, password, user_app_name), directConnection=True + ) # verify primary status assert client.is_primary, "Leader is not primary" @@ -93,7 +104,7 @@ async def test_exactly_one_primary(ops_test: OpsTest) -> None: """Tests that there is exactly one primary in the deployed units.""" try: password = await get_password(ops_test) - number_of_primaries = count_primaries(ops_test, password) + number_of_primaries = await count_primaries(ops_test, password) except RetryError: number_of_primaries = 0 @@ -106,11 +117,14 @@ async def test_exactly_one_primary(ops_test: OpsTest) -> None: async def test_get_primary_action(ops_test: OpsTest) -> None: """Tests that action get-primary outputs the correct unit with the primary replica.""" # determine which unit is the primary + app_name = await get_app_name(ops_test) expected_primary = None - for unit in ops_test.model.applications[APP_NAME].units: + for unit in ops_test.model.applications[app_name].units: # connect to mongod password = await get_password(ops_test) - client = MongoClient(unit_uri(unit.public_address, password), directConnection=True) + client = MongoClient( + unit_uri(unit.public_address, password, app_name), directConnection=True + ) # check primary status if client.is_primary: @@ -122,7 +136,7 @@ async def test_get_primary_action(ops_test: OpsTest) -> None: # check if get-primary returns the correct primary unit regardless of # which unit the action is run on - for unit in ops_test.model.applications[APP_NAME].units: + for unit in ops_test.model.applications[app_name].units: # use get-primary action to find primary action = await unit.run_action("get-primary") action = await action.wait() @@ -143,10 +157,13 @@ async def test_set_password_action(ops_test: OpsTest) -> None: assert new_password != old_password new_password_reported = await get_password(ops_test) assert new_password == new_password_reported + user_app_name = await get_app_name(ops_test) # verify that the password is updated in mongod by inserting into the collection. try: - client = MongoClient(unit_uri(unit.public_address, new_password), directConnection=True) + client = MongoClient( + unit_uri(unit.public_address, new_password, user_app_name), directConnection=True + ) client["new-db"].list_collection_names() except PyMongoError as e: assert False, f"Failed to access collection with new password, error: {e}" @@ -164,7 +181,9 @@ async def test_set_password_action(ops_test: OpsTest) -> None: # verify that the password is updated in mongod by inserting into the collection. try: - client = MongoClient(unit_uri(unit.public_address, "safe_pass"), directConnection=True) + client = MongoClient( + unit_uri(unit.public_address, "safe_pass", user_app_name), directConnection=True + ) client["new-db"].list_collection_names() except PyMongoError as e: assert False, f"Failed to access collection with new password, error: {e}" @@ -174,13 +193,14 @@ async def test_set_password_action(ops_test: OpsTest) -> None: async def test_monitor_user(ops_test: OpsTest) -> None: """Test verifies that the monitor user can perform operations such as 'rs.conf()'.""" - unit = ops_test.model.applications[APP_NAME].units[0] - password = await get_password(ops_test, "mongodb", "monitor") + app_name = await get_app_name(ops_test) + unit = ops_test.model.applications[app_name].units[0] + password = await get_password(ops_test, "monitor") replica_set_hosts = [ - unit.public_address for unit in ops_test.model.applications["mongodb"].units + unit.public_address for unit in ops_test.model.applications[app_name].units ] hosts = ",".join(replica_set_hosts) - replica_set_uri = f"mongodb://monitor:{password}@{hosts}/admin?replicaSet=mongodb" + replica_set_uri = f"mongodb://monitor:{password}@{hosts}/admin?replicaSet={app_name}" admin_mongod_cmd = f"{MONGO_SHELL} '{replica_set_uri}' --eval 'rs.conf()'" check_monitor_cmd = f"exec --unit {unit.name} -- {admin_mongod_cmd}" @@ -270,13 +290,13 @@ async def test_exactly_one_primary_reported_by_juju(ops_test: OpsTest) -> None: async def get_unit_messages(): """Collects unit status messages.""" - app = await app_name(ops_test) + app_name = await get_app_name(ops_test) unit_messages = {} async with ops_test.fast_forward(): time.sleep(20) - for unit in ops_test.model.applications[app].units: + for unit in ops_test.model.applications[app_name].units: unit_messages[unit.entity_id] = unit.workload_status_message return unit_messages