Skip to content

Commit

Permalink
fix: go into blocked status when database relation is removed (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
dariofaccin authored Nov 16, 2023
1 parent b9a2679 commit 87de55f
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 13 deletions.
9 changes: 9 additions & 0 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def __init__(self, *args):
],
)
self.framework.observe(self.on.database_relation_joined, self._configure_nrf)
self.framework.observe(self.on.database_relation_broken, self._on_database_relation_broken)
self.framework.observe(self.on.nrf_pebble_ready, self._configure_nrf)
self.framework.observe(self._database.on.database_created, self._configure_nrf)
self.framework.observe(
Expand Down Expand Up @@ -226,6 +227,14 @@ def _on_certificate_expiring(self, event: CertificateExpiringEvent) -> None:
return
self._request_new_certificate()

def _on_database_relation_broken(self, event: EventBase) -> None:
"""Event handler for database relation broken.
Args:
event: Juju event
"""
self.unit.status = BlockedStatus("Waiting for database relation")

def _generate_private_key(self) -> None:
"""Generates and stores private key."""
private_key = generate_private_key()
Expand Down
29 changes: 28 additions & 1 deletion tests/integration/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
METADATA = yaml.safe_load(Path("./metadata.yaml").read_text())
APP_NAME = METADATA["name"]
DB_APPLICATION_NAME = "mongodb"
DB_CHARM_NAME = "mongodb-k8s"
TLS_APPLICATION_NAME = "self-signed-certificates"


@pytest.fixture(scope="module")
@pytest.mark.abort_on_fail
async def deploy_mongodb(ops_test):
await ops_test.model.deploy(
"mongodb-k8s", application_name=DB_APPLICATION_NAME, channel="5/edge", trust=True
DB_CHARM_NAME, application_name=DB_APPLICATION_NAME, channel="5/edge", trust=True
)


Expand Down Expand Up @@ -98,6 +99,32 @@ async def test_restore_tls_and_wait_for_active_status(ops_test: OpsTest, build_a
await ops_test.model.wait_for_idle(apps=[APP_NAME], status="active", timeout=1000)


@pytest.mark.skip(
reason="Bug in MongoDB: https://github.com/canonical/mongodb-k8s-operator/issues/218"
)
@pytest.mark.abort_on_fail
async def test_remove_database_and_wait_for_blocked_status(ops_test: OpsTest, build_and_deploy):
assert ops_test.model
await ops_test.model.remove_application(DB_APPLICATION_NAME, block_until_done=True)
await ops_test.model.wait_for_idle(apps=[APP_NAME], status="blocked", timeout=60)


@pytest.mark.skip(
reason="Bug in MongoDB: https://github.com/canonical/mongodb-k8s-operator/issues/218"
)
@pytest.mark.abort_on_fail
async def test_restore_database_and_wait_for_active_status(ops_test: OpsTest, build_and_deploy):
assert ops_test.model
await ops_test.model.deploy(
DB_CHARM_NAME,
application_name=DB_APPLICATION_NAME,
channel="5/edge",
trust=True,
)
await ops_test.model.integrate(relation1=APP_NAME, relation2=DB_APPLICATION_NAME)
await ops_test.model.wait_for_idle(apps=[APP_NAME], status="active", timeout=1000)


@pytest.mark.abort_on_fail
async def test_when_scale_nrf_beyond_1_then_only_one_unit_is_active(
ops_test: OpsTest, build_and_deploy
Expand Down
56 changes: 44 additions & 12 deletions tests/unit/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,12 @@ def _create_database_relation(self) -> int:
)
return relation_id

def _database_is_available(self) -> None:
"""Create a database relation and set the database information."""
def _create_database_relation_and_populate_data(self) -> int:
"""Create a database relation and set the database information.
Returns:
relation_id: ID of the created relation
"""
database_relation_id = self._create_database_relation()
self.harness.update_relation_data(
relation_id=database_relation_id,
Expand All @@ -56,6 +60,7 @@ def _database_is_available(self) -> None:
"uris": "http://dummy",
},
)
return database_relation_id

@staticmethod
def _read_file(path: str) -> str:
Expand Down Expand Up @@ -90,6 +95,33 @@ def test_given_certificates_relation_not_created_when_pebble_ready_then_status_i
BlockedStatus(f"Waiting for {TLS_RELATION_NAME} relation to be created"),
)

@patch("ops.model.Container.pull")
@patch("ops.model.Container.exists")
@patch("ops.model.Container.push")
@patch("charm.check_output")
def test_given_nrf_charm_in_active_state_when_database_relation_breaks_then_status_is_blocked(
self,
patch_check_output,
patch_push,
patch_exists,
patch_pull,
):
patch_check_output.return_value = b"1.1.1.1"
patch_pull.return_value = StringIO(
self._read_file("tests/unit/expected_config/config.conf").strip()
)
patch_exists.return_value = True
database_relation_id = self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)
self.harness.container_pebble_ready(container_name="nrf")

self.harness.remove_relation(database_relation_id)

self.assertEqual(
self.harness.model.unit.status,
BlockedStatus("Waiting for database relation"),
)

def test_given_database_not_available_when_pebble_ready_then_status_is_waiting(
self,
):
Expand Down Expand Up @@ -118,7 +150,7 @@ def test_given_database_information_not_available_when_pebble_ready_then_status_
def test_given_storage_not_attached_when_pebble_ready_then_status_is_waiting(
self,
):
self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)
self.harness.container_pebble_ready(container_name="nrf")
self.assertEqual(
Expand All @@ -142,7 +174,7 @@ def test_given_certificates_not_stored_when_pebble_ready_then_status_is_waiting(
patch_check_output.return_value = b"1.1.1.1"
patch_exists.side_effect = [True, False, True, False]
self.harness.set_can_connect(container="nrf", val=True)
self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)
self.harness.container_pebble_ready("nrf")
self.assertEqual(
Expand Down Expand Up @@ -173,7 +205,7 @@ def test_given_database_info_and_storage_attached_and_certs_stored_when_pebble_r
event.certificate_signing_request = csr
patch_pull.side_effect = [StringIO(csr), StringIO("Dummy Content")]
patch_exists.side_effect = [True, True, False, False]
self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)
self.harness.charm._on_certificate_available(event=event)
self.harness.container_pebble_ready(container_name="nrf")
Expand All @@ -200,7 +232,7 @@ def test_given_content_of_config_file_not_changed_when_pebble_ready_then_config_
StringIO(self._read_file("tests/unit/expected_config/config.conf").strip()),
]
patch_exists.side_effect = [True, False, True]
self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.container_pebble_ready(container_name="nrf")
patch_push.assert_not_called()

Expand All @@ -221,7 +253,7 @@ def test_given_config_pushed_when_pebble_ready_then_pebble_plan_is_applied(
)
patch_exists.return_value = True

self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)

self.harness.container_pebble_ready(container_name="nrf")
Expand Down Expand Up @@ -264,7 +296,7 @@ def test_given_database_relation_is_created_and_config_file_is_written_when_pebb
)
patch_exists.return_value = True

self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)

self.harness.container_pebble_ready("nrf")
Expand All @@ -288,7 +320,7 @@ def test_given_ip_not_available_when_pebble_ready_then_status_is_waiting(
)
patch_exists.return_value = True

self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)

self.harness.container_pebble_ready(container_name="nrf")
Expand All @@ -312,7 +344,7 @@ def test_given_https_nrf_url_and_service_is_running_when_fiveg_nrf_relation_join
self._read_file("tests/unit/expected_config/config.conf").strip()
)

self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)

self.harness.set_can_connect(container="nrf", val=True)
Expand Down Expand Up @@ -360,7 +392,7 @@ def test_service_starts_running_after_nrf_relation_joined_when_fiveg_pebble_read
relation_id=relation_2_id, remote_unit_name="nrf-requirer-2/0"
)

self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)

self.harness.container_pebble_ready("nrf")
Expand Down Expand Up @@ -412,7 +444,7 @@ def test_given_certificates_are_stored_when_on_certificates_relation_broken_then
):
patch_exists.return_value = True
self.harness.set_can_connect(container="nrf", val=True)
self._database_is_available()
self._create_database_relation_and_populate_data()
self.harness.add_relation(relation_name=TLS_RELATION_NAME, remote_app=TLS_APPLICATION_NAME)
self.harness.charm._on_certificates_relation_broken(event=Mock())
self.assertEqual(
Expand Down

0 comments on commit 87de55f

Please sign in to comment.