Skip to content

Commit

Permalink
[DPE-3938] Preflight check tests (#396)
Browse files Browse the repository at this point in the history
## Issue
No tests for recent preflight check code

## Solution
add tests

---------

Co-authored-by: Mehdi Bendriss <[email protected]>
  • Loading branch information
MiaAltieri and Mehdi-Bendriss authored Apr 15, 2024
1 parent 35522f9 commit 7ddef1d
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 4 deletions.
4 changes: 2 additions & 2 deletions lib/charms/mongodb/v0/upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 1
LIBPATCH = 2


class MongoDBDependencyModel(BaseModel):
Expand Down Expand Up @@ -137,7 +137,7 @@ def is_replica_set_able_read_write(self) -> bool:
if not self.is_excepted_write_on_replica(secondary_ip, collection_name, write_value):
# do not return False immediately - as it is
logger.debug("Secondary with IP %s, does not contain the expected write.")
self.clear_tmp_collection(collection_name)
self.clear_tmp_collection(self.charm.mongodb_config, collection_name)
return False

self.clear_tmp_collection(self.charm.mongodb_config, collection_name)
Expand Down
3 changes: 1 addition & 2 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Config:
MONGODB_SNAP_DATA_DIR = "/var/snap/charmed-mongodb/current"
MONGOD_CONF_DIR = f"{MONGODB_SNAP_DATA_DIR}/etc/mongod"
MONGOD_CONF_FILE_PATH = f"{MONGOD_CONF_DIR}/mongod.conf"
SNAP_PACKAGES = [("charmed-mongodb", "6/edge", 117)]
SNAP_PACKAGES = [("charmed-mongodb", "6/edge", 118)]
DEPENDENCIES = {
"mongod_service": {
"dependencies": {},
Expand All @@ -31,7 +31,6 @@ class Config:
},
# TODO: Future PR DPE-3940 - implements mongos if necessary
}
SNAP_PACKAGES = [("charmed-mongodb", "6/edge", 118)]

# Keep these alphabetically sorted
class Actions:
Expand Down
1 change: 1 addition & 0 deletions tests/integration/upgrade/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Copyright 2023 Canonical Ltd.
69 changes: 69 additions & 0 deletions tests/integration/upgrade/test_upgrade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.

import logging
import os

import pytest
from pytest_operator.plugin import OpsTest

from ..ha_tests import helpers as ha_helpers
from ..helpers import check_or_scale_app, find_unit, get_app_name, unit_hostname

logger = logging.getLogger(__name__)


MEDIAN_REELECTION_TIME = 12


@pytest.mark.group(1)
@pytest.mark.skipif(
os.environ.get("PYTEST_SKIP_DEPLOY", False),
reason="skipping deploy, model expected to be provided.",
)
@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 await check_or_scale_app(ops_test, app_name)

my_charm = await ops_test.build_charm(".")
await ops_test.model.deploy(my_charm, num_units=3)
await ops_test.model.wait_for_idle()


@pytest.mark.group(1)
async def test_preflight_check(ops_test: OpsTest) -> None:
"""Verifies that the preflight check can run successfully."""
app_name = await get_app_name(ops_test)
leader_unit = await find_unit(ops_test, leader=True, app_name=app_name)
logger.info("Calling pre-upgrade-check")
action = await leader_unit.run_action("pre-upgrade-check")
await action.wait()
assert action.status == "completed", "pre-upgrade-check failed, expected to succeed."

await ops_test.model.wait_for_idle(
apps=[app_name], status="active", timeout=1000, idle_period=120
)


@pytest.mark.group(1)
async def test_preflight_check_failure(ops_test: OpsTest) -> None:
"""Verifies that the preflight check can run successfully."""
app_name = await get_app_name(ops_test)
unit = await find_unit(ops_test, leader=False, app_name=app_name)
leader_unit = await find_unit(ops_test, leader=True, app_name=app_name)
ha_helpers.cut_network_from_unit(await unit_hostname(ops_test, unit.name))

logger.info("Calling pre-upgrade-check")
action = await leader_unit.run_action("pre-upgrade-check")
await action.wait()
assert action.status == "failed", "pre-upgrade-check succeeded, expected to fail."

await ops_test.model.wait_for_idle(
apps=[app_name], status="active", timeout=1000, idle_period=120
)
69 changes: 69 additions & 0 deletions tests/unit/test_upgrade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.
import unittest
from unittest import mock
from unittest.mock import patch

from ops.model import ActiveStatus, BlockedStatus
from ops.testing import Harness

from charm import MongodbOperatorCharm

from .helpers import patch_network_get


class TestCharm(unittest.TestCase):
def setUp(self, *unused):
self.harness = Harness(MongodbOperatorCharm)
self.addCleanup(self.harness.cleanup)
self.harness.begin()
self.peer_rel_id = self.harness.add_relation("database-peers", "database-peers")

@patch_network_get(private_address="1.1.1.1")
@patch("charms.mongodb.v0.upgrade.MongoDBConnection")
def test_is_cluster_healthy(self, connection):
"""Test is_cluster_healthy function."""

def is_shard_mock_call(*args):
return args == ("shard",)

def is_replication_mock_call(*args):
return args == ("replication",)

active_status = mock.Mock()
active_status.return_value = ActiveStatus()

blocked_status = mock.Mock()
blocked_status.return_value = BlockedStatus()

# case 1: running on a shard
self.harness.charm.is_role = is_shard_mock_call
assert not self.harness.charm.upgrade.is_cluster_healthy()

# case 2: cluster is still syncing
self.harness.charm.is_role = is_replication_mock_call
self.harness.charm.process_statuses = active_status
connection.return_value.__enter__.return_value.is_any_sync.return_value = True
assert not self.harness.charm.upgrade.is_cluster_healthy()

# case 3: unit is not active
self.harness.charm.process_statuses = blocked_status
connection.return_value.__enter__.return_value.is_any_sync.return_value = False
assert not self.harness.charm.upgrade.is_cluster_healthy()

# # case 4: cluster is helathy
self.harness.charm.process_statuses = active_status
assert self.harness.charm.upgrade.is_cluster_healthy()

@patch_network_get(private_address="1.1.1.1")
@patch("charms.mongodb.v0.upgrade.MongoDBConnection")
@patch("charm.MongoDBUpgrade.is_excepted_write_on_replica")
def test_is_replica_set_able_read_write(self, is_excepted_write_on_replica, connection):
"""Test test_is_replica_set_able_read_write function."""
# case 1: writes are not present on secondaries
is_excepted_write_on_replica.return_value = False
assert not self.harness.charm.upgrade.is_replica_set_able_read_write()

# case 2: writes are present on secondaries
is_excepted_write_on_replica.return_value = True
assert self.harness.charm.upgrade.is_replica_set_able_read_write()

0 comments on commit 7ddef1d

Please sign in to comment.