--- /dev/null
+# Copyright 2021 Canonical Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact: legal@canonical.com
+#
+
+import pytest
+from ops import pebble
+from ops.model import ActiveStatus, BlockedStatus
+from ops.testing import Harness
+from pytest_mock import MockerFixture
+
+from charm import FERNET_KEY_REPOSITORY, KEYSTONE_FOLDER, KeystoneCharm
+
+
+@pytest.fixture
+def harness_no_relations(mocker: MockerFixture):
+ mocker.patch("charm.cluster")
+ mocker.patch("charm.KubernetesServicePatch")
+ keystone_harness = Harness(KeystoneCharm)
+ keystone_harness.begin()
+ container = keystone_harness.charm.unit.get_container("keystone")
+ keystone_harness.set_can_connect(container, True)
+ container.make_dir(KEYSTONE_FOLDER, make_parents=True)
+ container.make_dir(FERNET_KEY_REPOSITORY, make_parents=True)
+ container.push(f"{FERNET_KEY_REPOSITORY}0", "token")
+ container.make_dir("/app", make_parents=True)
+ container.push("/app/start.sh", "")
+ container.exec = mocker.Mock()
+ yield keystone_harness
+ keystone_harness.cleanup()
+
+
+@pytest.fixture
+def harness(harness_no_relations: Harness):
+ mysql_rel_id = harness_no_relations.add_relation("db", "mysql")
+ harness_no_relations.add_relation_unit(mysql_rel_id, "mysql/0")
+ harness_no_relations.update_relation_data(
+ mysql_rel_id,
+ "mysql/0",
+ {
+ "host": "host",
+ "port": "3306",
+ "user": "user",
+ "root_password": "root_pass",
+ "password": "password",
+ "database": "db",
+ },
+ )
+ return harness_no_relations
+
+
+def test_mysql_missing_relation(mocker: MockerFixture, harness_no_relations: Harness):
+ spy_safe_restart = mocker.spy(harness_no_relations.charm, "_safe_restart")
+ harness_no_relations.charm.on.keystone_pebble_ready.emit("keystone")
+ assert harness_no_relations.charm.unit.status == BlockedStatus("mysql relation is missing")
+ assert spy_safe_restart.call_count == 1
+ harness_no_relations.charm.on.config_changed.emit()
+ assert harness_no_relations.charm.unit.status == BlockedStatus("mysql relation is missing")
+ assert spy_safe_restart.call_count == 2
+
+
+def test_mysql_relation_ready(mocker: MockerFixture, harness: Harness):
+ spy = mocker.spy(harness.charm, "_safe_restart")
+ harness.charm.on.config_changed.emit()
+ assert harness.charm.unit.status == ActiveStatus()
+ assert spy.call_count == 1
+
+
+def test_db_sync_action(mocker: MockerFixture, harness: Harness):
+ event_mock = mocker.Mock()
+ harness.charm._on_db_sync_action(event_mock)
+ event_mock.set_results.assert_called_once_with(
+ {"output": "db-sync was successfully executed."}
+ )
+ event_mock.fail.assert_not_called()
+ harness.charm.container.exec().wait.side_effect = pebble.ExecError(
+ ["keystone-manage", "db_sync"], 1, "", "Error"
+ )
+ harness.charm._on_db_sync_action(event_mock)
+ event_mock.fail.assert_called_once_with("db-sync action failed with code 1 and stderr Error.")
+
+
+def test_provide_keystone_relation(mocker: MockerFixture, harness: Harness):
+ # Non-leader
+ mon_rel_id = harness.add_relation("keystone", "mon")
+ harness.add_relation_unit(mon_rel_id, "mon/0")
+ data = harness.get_relation_data(mon_rel_id, harness.charm.app)
+ assert data == {}
+ # Leader
+ harness.set_leader(True)
+ nbi_rel_id = harness.add_relation("keystone", "nbi")
+ harness.add_relation_unit(nbi_rel_id, "nbi/0")
+ data = harness.get_relation_data(nbi_rel_id, harness.charm.app)
+ assert data == {
+ "host": "http://osm-keystone:5000/v3",
+ "port": "5000",
+ "user_domain_name": "default",
+ "project_domain_name": "default",
+ "username": "nbi",
+ "password": "nbi",
+ "service": "service",
+ "keystone_db_password": "admin",
+ "region_id": "RegionOne",
+ "admin_username": "admin",
+ "admin_password": "admin",
+ "admin_project_name": "admin",
+ }
+
+
+def test_update_status_rotation(mocker: MockerFixture, harness: Harness):
+ spy_fernet_rotate = mocker.spy(harness.charm, "_fernet_rotate")
+ harness.set_leader(True)
+ harness._update_config({"token-expiration": -1})
+ harness.charm.on.update_status.emit()
+ assert spy_fernet_rotate.call_count == 1
+
+
+def test_update_status_no_rotation(mocker: MockerFixture, harness: Harness):
+ spy_fernet_rotate = mocker.spy(harness.charm, "_fernet_rotate")
+ harness.set_leader(True)
+ harness._update_config({"token-expiration": 3600})
+ harness.charm.on.update_status.emit()
+ assert spy_fernet_rotate.call_count == 0