Exemple #1
0
class TestEndpointAggregator(unittest.TestCase):
    def setUp(self):
        self.harness = Harness(EndpointAggregatorCharm, meta=AGGREGATOR_META)
        self.harness.set_model_info(name="testmodel", uuid="1234567890")
        self.addCleanup(self.harness.cleanup)
        self.harness.set_leader(True)
        self.harness.begin_with_initial_hooks()

    def test_adding_prometheus_then_target_forwards_a_labeled_scrape_job(self):
        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        target_rel_id = self.harness.add_relation(SCRAPE_TARGET_RELATION,
                                                  "target-app")
        self.harness.add_relation_unit(target_rel_id, "target-app/0")

        hostname = "scrape_target_0"
        port = "1234"
        self.harness.update_relation_data(
            target_rel_id,
            "target-app/0",
            {
                "hostname": f"{hostname}",
                "port": f"{port}",
            },
        )

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)
        scrape_jobs = json.loads(prometheus_rel_data.get("scrape_jobs", "[]"))
        expected_jobs = [{
            "job_name":
            "juju_testmodel_1234567_target-app_prometheus_scrape",
            "static_configs": [{
                "targets": ["scrape_target_0:1234"],
                "labels": {
                    "juju_model": "testmodel",
                    "juju_model_uuid": "1234567890",
                    "juju_application": "target-app",
                    "juju_unit": "target-app/0",
                    "host": "scrape_target_0",
                },
            }],
            "relabel_configs": [RELABEL_INSTANCE_CONFIG],
        }]
        self.assertListEqual(scrape_jobs, expected_jobs)

    def test_adding_prometheus_then_target_forwards_a_labeled_alert_rule(self):
        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        alert_rules_rel_id = self.harness.add_relation(ALERT_RULES_RELATION,
                                                       "rules-app")
        self.harness.add_relation_unit(alert_rules_rel_id, "rules-app/0")
        self.harness.update_relation_data(alert_rules_rel_id, "rules-app/0",
                                          {"groups": ALERT_RULE_1})

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)

        alert_rules = json.loads(prometheus_rel_data.get("alert_rules", "{}"))
        groups = alert_rules.get("groups", [])
        self.assertEqual(len(groups), 1)
        group = groups[0]

        expected_group = {
            "name":
            "juju_testmodel_1234567_rules-app_alert_rules",
            "rules": [{
                "alert": "CPU_Usage",
                "expr":
                'cpu_usage_idle{is_container!="True", group="promoagents-juju"} < 10',
                "for": "5m",
                "labels": {
                    "override_group_by": "host",
                    "severity": "page",
                    "cloud": "juju",
                    "juju_model": "testmodel",
                    "juju_model_uuid": "1234567",
                    "juju_application": "rules-app",
                    "juju_unit": "rules-app/0",
                },
                "annotations": {
                    "description":
                    "Host {{ $labels.host }} has had <  10% idle cpu for the last 5m\n",
                    "summary":
                    "Host {{ $labels.host }} CPU free is less than 10%",
                },
            }],
        }
        self.assertDictEqual(group, expected_group)

    def test_adding_target_then_prometheus_forwards_a_labeled_scrape_job(self):
        target_rel_id = self.harness.add_relation(SCRAPE_TARGET_RELATION,
                                                  "target-app")
        self.harness.add_relation_unit(target_rel_id, "target-app/0")

        hostname = "scrape_target_0"
        port = "1234"
        self.harness.update_relation_data(
            target_rel_id,
            "target-app/0",
            {
                "hostname": f"{hostname}",
                "port": f"{port}",
            },
        )

        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)
        scrape_jobs = json.loads(prometheus_rel_data.get("scrape_jobs", "[]"))
        expected_jobs = [{
            "job_name":
            "juju_testmodel_1234567_target-app_prometheus_scrape",
            "static_configs": [{
                "targets": ["scrape_target_0:1234"],
                "labels": {
                    "juju_model": "testmodel",
                    "juju_model_uuid": "1234567890",
                    "juju_application": "target-app",
                    "juju_unit": "target-app/0",
                    "host": "scrape_target_0",
                },
            }],
            "relabel_configs": [RELABEL_INSTANCE_CONFIG],
        }]
        self.assertListEqual(scrape_jobs, expected_jobs)

    def test_adding_target_then_prometheus_forwards_a_labeled_alert_rule(self):
        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        alert_rules_rel_id = self.harness.add_relation(ALERT_RULES_RELATION,
                                                       "rules-app")
        self.harness.add_relation_unit(alert_rules_rel_id, "rules-app/0")
        self.harness.update_relation_data(alert_rules_rel_id, "rules-app/0",
                                          {"groups": ALERT_RULE_1})

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)

        alert_rules = json.loads(prometheus_rel_data.get("alert_rules", "{}"))
        groups = alert_rules.get("groups", [])
        self.assertEqual(len(groups), 1)
        group = groups[0]

        expected_group = {
            "name":
            "juju_testmodel_1234567_rules-app_alert_rules",
            "rules": [{
                "alert": "CPU_Usage",
                "expr":
                'cpu_usage_idle{is_container!="True", group="promoagents-juju"} < 10',
                "for": "5m",
                "labels": {
                    "override_group_by": "host",
                    "severity": "page",
                    "cloud": "juju",
                    "juju_model": "testmodel",
                    "juju_model_uuid": "1234567",
                    "juju_application": "rules-app",
                    "juju_unit": "rules-app/0",
                },
                "annotations": {
                    "description":
                    "Host {{ $labels.host }} has had <  10% idle cpu for the last 5m\n",
                    "summary":
                    "Host {{ $labels.host }} CPU free is less than 10%",
                },
            }],
        }
        self.assertDictEqual(group, expected_group)

    def test_scrape_jobs_from_multiple_target_applications_are_forwarded(self):
        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        target_rel_id_1 = self.harness.add_relation(SCRAPE_TARGET_RELATION,
                                                    "target-app-1")
        self.harness.add_relation_unit(target_rel_id_1, "target-app-1/0")
        self.harness.update_relation_data(
            target_rel_id_1,
            "target-app-1/0",
            {
                "hostname": "scrape_target_0",
                "port": "1234",
            },
        )

        target_rel_id_2 = self.harness.add_relation(SCRAPE_TARGET_RELATION,
                                                    "target-app-2")
        self.harness.add_relation_unit(target_rel_id_2, "target-app-2/0")
        self.harness.update_relation_data(
            target_rel_id_2,
            "target-app-2/0",
            {
                "hostname": "scrape_target_1",
                "port": "5678",
            },
        )

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)
        scrape_jobs = json.loads(prometheus_rel_data.get("scrape_jobs", "[]"))
        self.assertEqual(len(scrape_jobs), 2)

        expected_jobs = [
            {
                "job_name":
                "juju_testmodel_1234567_target-app-1_prometheus_scrape",
                "static_configs": [{
                    "targets": ["scrape_target_0:1234"],
                    "labels": {
                        "juju_model": "testmodel",
                        "juju_model_uuid": "1234567890",
                        "juju_application": "target-app-1",
                        "juju_unit": "target-app-1/0",
                        "host": "scrape_target_0",
                    },
                }],
                "relabel_configs": [RELABEL_INSTANCE_CONFIG],
            },
            {
                "job_name":
                "juju_testmodel_1234567_target-app-2_prometheus_scrape",
                "static_configs": [{
                    "targets": ["scrape_target_1:5678"],
                    "labels": {
                        "juju_model": "testmodel",
                        "juju_model_uuid": "1234567890",
                        "juju_application": "target-app-2",
                        "juju_unit": "target-app-2/0",
                        "host": "scrape_target_1",
                    },
                }],
                "relabel_configs": [RELABEL_INSTANCE_CONFIG],
            },
        ]

        self.assertListEqual(scrape_jobs, expected_jobs)

    def test_alert_rules_from_multiple_target_applications_are_forwarded(self):
        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        alert_rules_rel_id_1 = self.harness.add_relation(
            ALERT_RULES_RELATION, "rules-app-1")
        self.harness.add_relation_unit(alert_rules_rel_id_1, "rules-app-1/0")
        self.harness.update_relation_data(
            alert_rules_rel_id_1,
            "rules-app-1/0",
            {"groups": ALERT_RULE_1},
        )

        alert_rules_rel_id_2 = self.harness.add_relation(
            ALERT_RULES_RELATION, "rules-app-2")
        self.harness.add_relation_unit(alert_rules_rel_id_2, "rules-app-2/0")
        self.harness.update_relation_data(
            alert_rules_rel_id_2,
            "rules-app-2/0",
            {"groups": ALERT_RULE_2},
        )

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)

        alert_rules = json.loads(prometheus_rel_data.get("alert_rules", "{}"))
        groups = alert_rules.get("groups", [])
        self.assertEqual(len(groups), 2)
        expected_groups = [
            {
                "name":
                "juju_testmodel_1234567_rules-app-1_alert_rules",
                "rules": [{
                    "alert": "CPU_Usage",
                    "expr":
                    'cpu_usage_idle{is_container!="True", group="promoagents-juju"} < 10',
                    "for": "5m",
                    "labels": {
                        "override_group_by": "host",
                        "severity": "page",
                        "cloud": "juju",
                        "juju_model": "testmodel",
                        "juju_model_uuid": "1234567",
                        "juju_application": "rules-app-1",
                        "juju_unit": "rules-app-1/0",
                    },
                    "annotations": {
                        "description":
                        "Host {{ $labels.host }} has had <  10% idle cpu for the last 5m\n",
                        "summary":
                        "Host {{ $labels.host }} CPU free is less than 10%",
                    },
                }],
            },
            {
                "name":
                "juju_testmodel_1234567_rules-app-2_alert_rules",
                "rules": [{
                    "alert": "DiskFull",
                    "expr":
                    'disk_free{is_container!="True", fstype!~".*tmpfs|squashfs|overlay"}  <1024',
                    "for": "5m",
                    "labels": {
                        "override_group_by": "host",
                        "severity": "page",
                        "juju_model": "testmodel",
                        "juju_model_uuid": "1234567",
                        "juju_application": "rules-app-2",
                        "juju_unit": "rules-app-2/0",
                    },
                    "annotations": {
                        "description":
                        "Host {{ $labels.host}} {{ $labels.path }} is full\nsummary: Host {{ $labels.host }} {{ $labels.path}} is full\n"
                    },
                }],
            },
        ]
        self.assertListEqual(groups, expected_groups)

    def test_scrape_job_removal_differentiates_between_applications(self):
        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        target_rel_id_1 = self.harness.add_relation("prometheus-target",
                                                    "target-app-1")
        self.harness.add_relation_unit(target_rel_id_1, "target-app-1/0")
        self.harness.update_relation_data(
            target_rel_id_1,
            "target-app-1/0",
            {
                "hostname": "scrape_target_0",
                "port": "1234",
            },
        )

        target_rel_id_2 = self.harness.add_relation("prometheus-target",
                                                    "target-app-2")
        self.harness.add_relation_unit(target_rel_id_2, "target-app-2/0")
        self.harness.update_relation_data(
            target_rel_id_2,
            "target-app-2/0",
            {
                "hostname": "scrape_target_1",
                "port": "5678",
            },
        )

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)
        scrape_jobs = json.loads(prometheus_rel_data.get("scrape_jobs", "[]"))
        self.assertEqual(len(scrape_jobs), 2)

        self.harness.remove_relation_unit(target_rel_id_2, "target-app-2/0")
        scrape_jobs = json.loads(prometheus_rel_data.get("scrape_jobs", "[]"))
        self.assertEqual(len(scrape_jobs), 1)

        expected_jobs = [{
            "job_name":
            "juju_testmodel_1234567_target-app-1_prometheus_scrape",
            "static_configs": [{
                "targets": ["scrape_target_0:1234"],
                "labels": {
                    "juju_model": "testmodel",
                    "juju_model_uuid": "1234567890",
                    "juju_application": "target-app-1",
                    "juju_unit": "target-app-1/0",
                    "host": "scrape_target_0",
                },
            }],
            "relabel_configs": [RELABEL_INSTANCE_CONFIG],
        }]
        self.assertListEqual(scrape_jobs, expected_jobs)

    def test_alert_rules_removal_differentiates_between_applications(self):
        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        alert_rules_rel_id_1 = self.harness.add_relation(
            "prometheus-rules", "rules-app-1")
        self.harness.add_relation_unit(alert_rules_rel_id_1, "rules-app-1/0")
        self.harness.update_relation_data(
            alert_rules_rel_id_1,
            "rules-app-1/0",
            {"groups": ALERT_RULE_1},
        )

        alert_rules_rel_id_2 = self.harness.add_relation(
            "prometheus-rules", "rules-app-2")
        self.harness.add_relation_unit(alert_rules_rel_id_2, "rules-app-2/0")
        self.harness.update_relation_data(
            alert_rules_rel_id_2,
            "rules-app-2/0",
            {"groups": ALERT_RULE_2},
        )

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)

        alert_rules = json.loads(prometheus_rel_data.get("alert_rules", "{}"))
        groups = alert_rules.get("groups", [])
        self.assertEqual(len(groups), 2)

        self.harness.remove_relation_unit(alert_rules_rel_id_2,
                                          "rules-app-2/0")
        alert_rules = json.loads(prometheus_rel_data.get("alert_rules", "{}"))
        groups = alert_rules.get("groups", [])
        self.assertEqual(len(groups), 1)

        expected_groups = [
            {
                "name":
                "juju_testmodel_1234567_rules-app-1_alert_rules",
                "rules": [{
                    "alert": "CPU_Usage",
                    "expr":
                    'cpu_usage_idle{is_container!="True", group="promoagents-juju"} < 10',
                    "for": "5m",
                    "labels": {
                        "override_group_by": "host",
                        "severity": "page",
                        "cloud": "juju",
                        "juju_model": "testmodel",
                        "juju_model_uuid": "1234567",
                        "juju_application": "rules-app-1",
                        "juju_unit": "rules-app-1/0",
                    },
                    "annotations": {
                        "description":
                        "Host {{ $labels.host }} has had <  10% idle cpu for the last 5m\n",
                        "summary":
                        "Host {{ $labels.host }} CPU free is less than 10%",
                    },
                }],
            },
        ]

        self.assertListEqual(groups, expected_groups)

    def test_removing_scrape_jobs_differentiates_between_units(self):
        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        target_rel_id = self.harness.add_relation("prometheus-target",
                                                  "target-app")
        self.harness.add_relation_unit(target_rel_id, "target-app/0")
        self.harness.update_relation_data(
            target_rel_id,
            "target-app/0",
            {
                "hostname": "scrape_target_0",
                "port": "1234",
            },
        )

        self.harness.add_relation_unit(target_rel_id, "target-app/1")
        self.harness.update_relation_data(
            target_rel_id,
            "target-app/1",
            {
                "hostname": "scrape_target_1",
                "port": "5678",
            },
        )

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)
        scrape_jobs = json.loads(prometheus_rel_data.get("scrape_jobs", "[]"))

        self.assertEqual(len(scrape_jobs), 1)
        self.assertEqual(len(scrape_jobs[0].get("static_configs")), 2)

        self.harness.remove_relation_unit(target_rel_id, "target-app/1")
        scrape_jobs = json.loads(prometheus_rel_data.get("scrape_jobs", "[]"))

        self.assertEqual(len(scrape_jobs), 1)
        self.assertEqual(len(scrape_jobs[0].get("static_configs")), 1)

        expected_jobs = [{
            "job_name":
            "juju_testmodel_1234567_target-app_prometheus_scrape",
            "static_configs": [{
                "targets": ["scrape_target_0:1234"],
                "labels": {
                    "juju_model": "testmodel",
                    "juju_model_uuid": "1234567890",
                    "juju_application": "target-app",
                    "juju_unit": "target-app/0",
                    "host": "scrape_target_0",
                },
            }],
            "relabel_configs": [RELABEL_INSTANCE_CONFIG],
        }]
        self.assertListEqual(scrape_jobs, expected_jobs)

    def test_removing_alert_rules_differentiates_between_units(self):
        prometheus_rel_id = self.harness.add_relation(PROMETHEUS_RELATION,
                                                      "prometheus")
        self.harness.add_relation_unit(prometheus_rel_id, "prometheus/0")

        alert_rules_rel_id = self.harness.add_relation("prometheus-rules",
                                                       "rules-app")
        self.harness.add_relation_unit(alert_rules_rel_id, "rules-app/0")
        self.harness.update_relation_data(
            alert_rules_rel_id,
            "rules-app/0",
            {"groups": ALERT_RULE_1},
        )

        self.harness.add_relation_unit(alert_rules_rel_id, "rules-app/1")
        self.harness.update_relation_data(
            alert_rules_rel_id,
            "rules-app/1",
            {"groups": ALERT_RULE_2},
        )

        prometheus_rel_data = self.harness.get_relation_data(
            prometheus_rel_id, self.harness.model.app.name)

        alert_rules = json.loads(prometheus_rel_data.get("alert_rules", "{}"))
        groups = alert_rules.get("groups", [])
        self.assertEqual(len(groups), 1)

        self.harness.remove_relation_unit(alert_rules_rel_id, "rules-app/1")

        alert_rules = json.loads(prometheus_rel_data.get("alert_rules", "{}"))
        groups = alert_rules.get("groups", [])
        self.assertEqual(len(groups), 1)

        expected_groups = [
            {
                "name":
                "juju_testmodel_1234567_rules-app_alert_rules",
                "rules": [{
                    "alert": "CPU_Usage",
                    "expr":
                    'cpu_usage_idle{is_container!="True", group="promoagents-juju"} < 10',
                    "for": "5m",
                    "labels": {
                        "override_group_by": "host",
                        "severity": "page",
                        "cloud": "juju",
                        "juju_model": "testmodel",
                        "juju_model_uuid": "1234567",
                        "juju_application": "rules-app",
                        "juju_unit": "rules-app/0",
                    },
                    "annotations": {
                        "description":
                        "Host {{ $labels.host }} has had <  10% idle cpu for the last 5m\n",
                        "summary":
                        "Host {{ $labels.host }} CPU free is less than 10%",
                    },
                }],
            },
        ]
        self.assertListEqual(groups, expected_groups)
Exemple #2
0
class TestSharedDBRelation(unittest.TestCase):
    def setUp(self):
        self.harness = Harness(MySQLOperatorCharm)
        self.addCleanup(self.harness.cleanup)
        self.harness.begin()
        self.peer_relation_id = self.harness.add_relation(
            "database-peers", "database-peers")
        self.harness.add_relation_unit(self.peer_relation_id, "mysql/1")
        self.shared_db_relation_id = self.harness.add_relation(
            LEGACY_DB_SHARED, "other-app")
        self.harness.add_relation_unit(self.shared_db_relation_id,
                                       "other-app/0")
        self.charm = self.harness.charm

    @patch_network_get(private_address="1.1.1.1")
    @patch("mysqlsh_helpers.MySQL.get_cluster_primary_address",
           return_value="1.1.1.1")
    @patch("relations.shared_db.generate_random_password",
           return_value="super_secure_password")
    @patch("mysqlsh_helpers.MySQL.create_application_database_and_scoped_user")
    def test_shared_db_relation_changed(
        self,
        _create_application_database_and_scoped_user,
        _generate_random_password,
        _get_cluster_primary_address,
    ):
        # run start-up events to enable usage of the helper class
        self.harness.set_leader(True)
        self.charm.on.config_changed.emit()

        # confirm that the relation databag is empty
        shared_db_relation_databag = self.harness.get_relation_data(
            self.shared_db_relation_id, self.harness.charm.app)
        shared_db_relation = self.charm.model.get_relation(LEGACY_DB_SHARED)
        app_unit = list(shared_db_relation.units)[0]

        self.assertEqual(shared_db_relation_databag, {})
        self.assertEqual(shared_db_relation.data.get(app_unit), {})
        self.assertEqual(shared_db_relation.data.get(self.charm.unit), {})

        # update the app leader unit data to trigger shared_db_relation_changed event
        self.harness.update_relation_data(
            self.shared_db_relation_id,
            "other-app/0",
            {
                "database": "shared_database",
                "hostname": "1.1.1.2",
                "username": "******",
                "private-address": "1.1.1.3",
            },
        )

        # 2 calls during start-up events, and 1 calls during the shared_db_relation_changed event
        self.assertEqual(_generate_random_password.call_count, 1)
        _create_application_database_and_scoped_user.assert_called_once_with(
            "shared_database", "shared_user", "super_secure_password",
            "1.1.1.3", "other-app/0")

        # confirm that the relation databag is populated
        self.assertEqual(
            shared_db_relation.data.get(self.charm.unit),
            {
                "db_host": "1.1.1.1",
                "db_port": "3306",
                "wait_timeout": "3600",
                "password": "******",
                "allowed_units": "other-app/0",
            },
        )

    @patch_network_get(private_address="1.1.1.1")
    @patch("utils.generate_random_password",
           return_value="super_secure_password")
    @patch("mysqlsh_helpers.MySQL.create_application_database_and_scoped_user")
    def test_shared_db_relation_changed_error_on_user_creation(
            self, _create_application_database_and_scoped_user,
            _generate_random_password):
        # run start-up events to enable usage of the helper class
        self.harness.set_leader(True)
        self.charm.on.config_changed.emit()

        _create_application_database_and_scoped_user.side_effect = (
            MySQLCreateApplicationDatabaseAndScopedUserError(
                "Can't create user"))
        # update the app leader unit data to trigger shared_db_relation_changed event
        self.harness.update_relation_data(
            self.shared_db_relation_id,
            "other-app/0",
            {
                "database": "shared_database",
                "hostname": "1.1.1.2",
                "username": "******",
            },
        )

        self.assertTrue(
            isinstance(self.harness.model.unit.status, BlockedStatus))

    @patch_network_get(private_address="1.1.1.1")
    @patch("mysqlsh_helpers.MySQL.get_cluster_primary_address",
           return_value="1.1.1.1:3306")
    @patch("mysqlsh_helpers.MySQL.delete_users_for_unit")
    @patch("relations.shared_db.generate_random_password",
           return_value="super_secure_password")
    @patch("mysqlsh_helpers.MySQL.create_application_database_and_scoped_user")
    def test_shared_db_relation_departed(
        self,
        _create_application_database_and_scoped_user,
        _generate_random_password,
        _delete_users_for_unit,
        _get_cluster_primary_address,
    ):
        # run start-up events to enable usage of the helper class
        self.harness.set_leader(True)
        self.charm.on.config_changed.emit()

        # update the app leader unit data to trigger shared_db_relation_changed event
        self.harness.update_relation_data(
            self.shared_db_relation_id,
            "other-app/0",
            {
                "database": "shared_database",
                "hostname": "1.1.1.2",
                "username": "******",
                "private-address": "1.1.1.2",
            },
        )

        # Workaround ops.testing not setting `departing_unit` in v1.5.0
        # ref https://github.com/canonical/operator/pull/790
        shared_db_relation = self.charm.model.get_relation(LEGACY_DB_SHARED)
        with patch.object(RelationDepartedEvent,
                          "departing_unit",
                          new_callable=PropertyMock) as mock_departing_unit:
            mock_departing_unit.return_value = list(
                shared_db_relation.units)[0]
            self.harness.remove_relation_unit(self.shared_db_relation_id,
                                              "other-app/0")

        _delete_users_for_unit.assert_called_once_with("other-app/0")