Skip to content

Commit

Permalink
WIP: Fix user creation and unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitry-ratushnyy committed Nov 28, 2023
1 parent e562899 commit d1e6e03
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 22 deletions.
19 changes: 10 additions & 9 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
ServiceInfo,
)
from pymongo.errors import PyMongoError
from tenacity import before_log, retry, stop_after_attempt, wait_fixed
from tenacity import RetryError, before_log, retry, stop_after_attempt, wait_fixed

from config import Config
from exceptions import AdminUserCreationError, MissingSecretError
Expand Down Expand Up @@ -406,7 +406,11 @@ def _on_start(self, event) -> None:
return

self._initialise_replica_set(event)
self._initialise_users(event)
try:
self._initialise_users(event)
except RetryError:
event.defer()
return

# mongod is now active
self.unit.status = ActiveStatus()
Expand Down Expand Up @@ -613,7 +617,6 @@ def _on_secret_changed(self, event):
@retry(
stop=stop_after_attempt(USER_CREATING_MAX_ATTEMPTS),
wait=wait_fixed(USER_CREATION_COOLDOWN),
reraise=True,
before=before_log(logger, logging.DEBUG),
)
def _initialise_users(self, event: StartEvent) -> None:
Expand Down Expand Up @@ -644,16 +647,14 @@ def _initialise_users(self, event: StartEvent) -> None:
self.users_initialized = True
except ExecError as e:
logger.error("Deferring on_start: exit code: %i, stderr: %s", e.exit_code, e.stderr)
event.defer()
raise e # we need to raise to make retry work
raise # we need to raise to make retry work
except PyMongoError as e:
logger.error("Deferring on_start since: error=%r", e)
event.defer()
raise e # we need to raise to make retry work
except AdminUserCreationError as e:
raise # we need to raise to make retry work
except AdminUserCreationError:
logger.error("Deferring on_start: Failed to create operator user.")
event.defer()
raise e # we need to raise to make retry work
raise # we need to raise to make retry work

@retry(
stop=stop_after_attempt(3),
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ async def test_no_password_change_on_invalid_password(ops_test: OpsTest) -> None
password1 = await get_password(ops_test, unit_id=leader_id, username="monitor")

# The password has to be minimum 3 characters
await set_password(ops_test, unit_id=leader_id, username="monitor", password="ca" * 2048)
await set_password(ops_test, unit_id=leader_id, username="monitor", password="ca" * 1000000)
password2 = await get_password(ops_test, unit_id=leader_id, username="monitor")

# The password didn't change
Expand Down
27 changes: 15 additions & 12 deletions tests/unit/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
OperationFailure,
PyMongoError,
)
from tenacity import RetryError

from charm import MongoDBCharm, NotReadyError
from charm import USER_CREATING_MAX_ATTEMPTS, MongoDBCharm, NotReadyError

from .helpers import patch_network_get

Expand Down Expand Up @@ -295,6 +296,7 @@ def test_start_already_initialised(self, connection, init_user, provider, defer)
self.harness.charm.unit.get_container = mock_container

self.harness.charm.app_peer_data["db_initialised"] = "True"
self.harness.charm.app_peer_data["users_initialized"] = "True"

self.harness.charm.on.start.emit()

Expand Down Expand Up @@ -395,7 +397,7 @@ def test_start_mongod_error_initalising_user(self, connection, init_user, provid
defer.assert_called()

# verify app data
self.assertEqual("db_initialised" in self.harness.charm.app_peer_data, False)
self.assertEqual("users_initialized" in self.harness.charm.app_peer_data, False)

@patch("ops.framework.EventBase.defer")
@patch("charm.MongoDBProvider")
Expand Down Expand Up @@ -428,7 +430,7 @@ def test_start_mongod_error_overseeing_users(self, connection, init_user, provid
defer.assert_called()

# verify app data
self.assertEqual("db_initialised" in self.harness.charm.app_peer_data, False)
self.assertEqual("users_initialized" in self.harness.charm.app_peer_data, False)

@patch("ops.framework.EventBase.defer")
@patch("charm.MongoDBConnection")
Expand Down Expand Up @@ -595,14 +597,13 @@ def test_reconfigure_add_member_failure(self, connection, defer):
connection.return_value.__enter__.return_value.add_replset_member.assert_called()
defer.assert_called()

@patch("charm.MongoDBCharm._initialise_users")
@patch("ops.framework.EventBase.defer")
@patch("charm.MongoDBProvider.oversee_users")
@patch("charm.MongoDBConnection")
@patch("tenacity.nap.time.sleep", MagicMock())
@patch("charm.USER_CREATING_MAX_ATTEMPTS", 1)
@patch("charm.USER_CREATION_COOLDOWN", 1)
@patch("charm.REPLICA_SET_INIT_CHECK_TIMEOUT", 1)
def test_start_init_operator_user_after_second_call(self, connection, oversee_users, defer):
def test_start_init_operator_user_after_second_call(
self, connection, oversee_users, defer, _initialise_users
):
"""Tests that the creation of the admin user is only performed once.
Verifies that if the user is already set up, that no attempts to set it up again are
Expand All @@ -619,6 +620,7 @@ def test_start_init_operator_user_after_second_call(self, connection, oversee_us
connection.return_value.__enter__.return_value.is_ready = True

oversee_users.side_effect = PyMongoError()
_initialise_users.side_effect = RetryError(last_attempt=USER_CREATING_MAX_ATTEMPTS)

self.harness.charm.on.start.emit()

Expand Down Expand Up @@ -910,6 +912,10 @@ def test__connect_mongodb_exporter_success(
expected_uri = uri_template.format(password="mongo123")
self.assertEqual(expected_uri, new_uri)

@patch("tenacity.nap.time.sleep", MagicMock())
@patch("charm.USER_CREATING_MAX_ATTEMPTS", 1)
@patch("charm.USER_CREATION_COOLDOWN", 1)
@patch("charm.REPLICA_SET_INIT_CHECK_TIMEOUT", 1)
@patch("charm.MongoDBCharm._init_operator_user")
@patch("charm.MongoDBCharm._init_monitor_user")
@patch("charm.MongoDBCharm._connect_mongodb_exporter")
Expand All @@ -918,10 +924,6 @@ def test__connect_mongodb_exporter_success(
@patch("ops.framework.EventBase.defer")
@patch("charm.MongoDBCharm._set_data_dir_permissions")
@patch("charm.MongoDBConnection")
@patch("tenacity.nap.time.sleep", MagicMock())
@patch("charm.USER_CREATING_MAX_ATTEMPTS", 1)
@patch("charm.USER_CREATION_COOLDOWN", 1)
@patch("charm.REPLICA_SET_INIT_CHECK_TIMEOUT", 1)
def test__backup_user_created(
self,
connection,
Expand All @@ -936,6 +938,7 @@ def test__backup_user_created(
"""Tests what backup user was created."""
container = self.harness.model.unit.get_container("mongod")
self.harness.set_can_connect(container, True)
self.harness.charm.app_peer_data["db_initialised"] = "True"
self.harness.charm.on.start.emit()
password = self.harness.charm.get_secret("app", "backup-password")
self.assertIsNotNone(password) # verify the password is set
Expand Down

0 comments on commit d1e6e03

Please sign in to comment.