Skip to content

Commit

Permalink
Charm integration
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitry-ratushnyy committed Jan 4, 2024
1 parent 41b45f0 commit e8c0ca9
Showing 1 changed file with 40 additions and 20 deletions.
60 changes: 40 additions & 20 deletions tests/integration/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -30,7 +31,6 @@

logger = logging.getLogger(__name__)

ANOTHER_DATABASE_APP_NAME = "another-database-a"

MEDIAN_REELECTION_TIME = 12

Expand All @@ -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()
Expand All @@ -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:
Expand All @@ -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"
Expand All @@ -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

Expand All @@ -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:
Expand All @@ -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()
Expand All @@ -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}"
Expand All @@ -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}"
Expand All @@ -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}"
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e8c0ca9

Please sign in to comment.