#!/usr/bin/env python3
# Copyright 2020 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
#
# To get in touch with the maintainers, please contact:
# osm-charmers@lists.launchpad.net
##

from typing import NoReturn
import unittest
from ops.model import BlockedStatus

from ops.testing import Harness

from charm import NbiCharm


class TestCharm(unittest.TestCase):
    """NBI Charm unit tests."""

    def setUp(self) -> NoReturn:
        """Test setup"""
        self.harness = Harness(NbiCharm)
        self.harness.set_leader(is_leader=True)
        self.harness.begin()

    def test_on_start_without_relations(self) -> NoReturn:
        """Test installation without any relation."""
        self.harness.charm.on.start.emit()

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertIn("kafka", self.harness.charm.unit.status.message)
        self.assertIn("mongodb", self.harness.charm.unit.status.message)
        self.assertIn("prometheus", self.harness.charm.unit.status.message)
        self.assertNotIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_on_start_without_relations_with_keystone(self) -> NoReturn:
        """Test installation without any relation and keystone enabled."""
        self.harness.update_config({"auth_backend": "keystone"})

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

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertIn("kafka", self.harness.charm.unit.status.message)
        self.assertIn("mongodb", self.harness.charm.unit.status.message)
        self.assertIn("prometheus", self.harness.charm.unit.status.message)
        self.assertIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_on_start_with_relations(self) -> NoReturn:
        """Test deployment without keystone."""
        expected_result = {
            "version": 3,
            "containers": [
                {
                    "name": "nbi",
                    "imageDetails": self.harness.charm.image.fetch(),
                    "imagePullPolicy": "Always",
                    "ports": [
                        {
                            "name": "nbi",
                            "containerPort": 9999,
                            "protocol": "TCP",
                        }
                    ],
                    "envConfig": {
                        "ALLOW_ANONYMOUS_LOGIN": "yes",
                        "OSMNBI_SERVER_ENABLE_TEST": False,
                        "OSMNBI_STATIC_DIR": "/app/osm_nbi/html_public",
                        "OSMNBI_MESSAGE_HOST": "kafka",
                        "OSMNBI_MESSAGE_DRIVER": "kafka",
                        "OSMNBI_MESSAGE_PORT": 9092,
                        "OSMNBI_DATABASE_DRIVER": "mongo",
                        "OSMNBI_DATABASE_URI": "mongodb://mongo:27017",
                        "OSMNBI_DATABASE_COMMONKEY": "osm",
                        "OSMNBI_STORAGE_DRIVER": "mongo",
                        "OSMNBI_STORAGE_PATH": "/app/storage",
                        "OSMNBI_STORAGE_COLLECTION": "files",
                        "OSMNBI_STORAGE_URI": "mongodb://mongo:27017",
                        "OSMNBI_PROMETHEUS_HOST": "prometheus",
                        "OSMNBI_PROMETHEUS_PORT": 9090,
                        "OSMNBI_LOG_LEVEL": "INFO",
                        "OSMNBI_AUTHENTICATION_BACKEND": "internal",
                    },
                }
            ],
            "kubernetesResources": {
                "ingressResources": [],
            },
        }

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

        # Check if kafka datastore is initialized
        self.assertIsNone(self.harness.charm.state.message_host)
        self.assertIsNone(self.harness.charm.state.message_port)

        # Check if mongodb datastore is initialized
        self.assertIsNone(self.harness.charm.state.database_uri)

        # Check if prometheus datastore is initialized
        self.assertIsNone(self.harness.charm.state.prometheus_host)
        self.assertIsNone(self.harness.charm.state.prometheus_port)

        # Initializing the kafka relation
        kafka_relation_id = self.harness.add_relation("kafka", "kafka")
        self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
        self.harness.update_relation_data(
            kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
        )

        # Initializing the mongo relation
        mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
        self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
        self.harness.update_relation_data(
            mongodb_relation_id,
            "mongodb/0",
            {"connection_string": "mongodb://mongo:27017"},
        )

        # Initializing the prometheus relation
        prometheus_relation_id = self.harness.add_relation("prometheus", "prometheus")
        self.harness.add_relation_unit(prometheus_relation_id, "prometheus/0")
        self.harness.update_relation_data(
            prometheus_relation_id,
            "prometheus/0",
            {"hostname": "prometheus", "port": 9090},
        )

        # Checking if kafka data is stored
        self.assertEqual(self.harness.charm.state.message_host, "kafka")
        self.assertEqual(self.harness.charm.state.message_port, 9092)

        # Checking if mongodb data is stored
        self.assertEqual(self.harness.charm.state.database_uri, "mongodb://mongo:27017")

        # Checking if prometheus data is stored
        self.assertEqual(self.harness.charm.state.prometheus_host, "prometheus")
        self.assertEqual(self.harness.charm.state.prometheus_port, 9090)

        # Verifying status
        self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)

        pod_spec, _ = self.harness.get_pod_spec()

        self.assertDictEqual(expected_result, pod_spec)

    def test_on_start_with_relations_with_keystone(self) -> NoReturn:
        """Test deployment with keystone."""
        expected_result = {
            "version": 3,
            "containers": [
                {
                    "name": "nbi",
                    "imageDetails": self.harness.charm.image.fetch(),
                    "imagePullPolicy": "Always",
                    "ports": [
                        {
                            "name": "nbi",
                            "containerPort": 9999,
                            "protocol": "TCP",
                        }
                    ],
                    "envConfig": {
                        "ALLOW_ANONYMOUS_LOGIN": "yes",
                        "OSMNBI_SERVER_ENABLE_TEST": False,
                        "OSMNBI_STATIC_DIR": "/app/osm_nbi/html_public",
                        "OSMNBI_MESSAGE_HOST": "kafka",
                        "OSMNBI_MESSAGE_DRIVER": "kafka",
                        "OSMNBI_MESSAGE_PORT": 9092,
                        "OSMNBI_DATABASE_DRIVER": "mongo",
                        "OSMNBI_DATABASE_URI": "mongodb://mongo:27017",
                        "OSMNBI_DATABASE_COMMONKEY": "osm",
                        "OSMNBI_STORAGE_DRIVER": "mongo",
                        "OSMNBI_STORAGE_PATH": "/app/storage",
                        "OSMNBI_STORAGE_COLLECTION": "files",
                        "OSMNBI_STORAGE_URI": "mongodb://mongo:27017",
                        "OSMNBI_PROMETHEUS_HOST": "prometheus",
                        "OSMNBI_PROMETHEUS_PORT": 9090,
                        "OSMNBI_LOG_LEVEL": "INFO",
                        "OSMNBI_AUTHENTICATION_BACKEND": "keystone",
                        "OSMNBI_AUTHENTICATION_AUTH_URL": "keystone",
                        "OSMNBI_AUTHENTICATION_AUTH_PORT": 5000,
                        "OSMNBI_AUTHENTICATION_USER_DOMAIN_NAME": "default",
                        "OSMNBI_AUTHENTICATION_PROJECT_DOMAIN_NAME": "default",
                        "OSMNBI_AUTHENTICATION_SERVICE_USERNAME": "nbi",
                        "OSMNBI_AUTHENTICATION_SERVICE_PASSWORD": "nbi",
                        "OSMNBI_AUTHENTICATION_SERVICE_PROJECT": "service",
                    },
                }
            ],
            "kubernetesResources": {
                "ingressResources": [],
            },
        }

        self.harness.update_config({"auth_backend": "keystone"})

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

        # Check if kafka datastore is initialized
        self.assertIsNone(self.harness.charm.state.message_host)
        self.assertIsNone(self.harness.charm.state.message_port)

        # Check if mongodb datastore is initialized
        self.assertIsNone(self.harness.charm.state.database_uri)

        # Check if prometheus datastore is initialized
        self.assertIsNone(self.harness.charm.state.prometheus_host)
        self.assertIsNone(self.harness.charm.state.prometheus_port)

        # Check if keystone datastore is initialized
        self.assertIsNone(self.harness.charm.state.keystone_host)
        self.assertIsNone(self.harness.charm.state.keystone_port)
        self.assertIsNone(self.harness.charm.state.keystone_user_domain_name)
        self.assertIsNone(self.harness.charm.state.keystone_project_domain_name)
        self.assertIsNone(self.harness.charm.state.keystone_username)
        self.assertIsNone(self.harness.charm.state.keystone_password)
        self.assertIsNone(self.harness.charm.state.keystone_service)

        # Initializing the kafka relation
        kafka_relation_id = self.harness.add_relation("kafka", "kafka")
        self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
        self.harness.update_relation_data(
            kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
        )

        # Initializing the mongodb relation
        mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
        self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
        self.harness.update_relation_data(
            mongodb_relation_id,
            "mongodb/0",
            {"connection_string": "mongodb://mongo:27017"},
        )

        # Initializing the prometheus relation
        promethues_relation_id = self.harness.add_relation("prometheus", "prometheus")
        self.harness.add_relation_unit(promethues_relation_id, "prometheus/0")
        self.harness.update_relation_data(
            promethues_relation_id,
            "prometheus/0",
            {"hostname": "prometheus", "port": 9090},
        )

        # Initializing the keystone relation
        keystone_relation_id = self.harness.add_relation("keystone", "keystone")
        self.harness.add_relation_unit(keystone_relation_id, "keystone/0")
        self.harness.update_relation_data(
            keystone_relation_id,
            "keystone/0",
            {
                "host": "keystone",
                "port": 5000,
                "user_domain_name": "default",
                "project_domain_name": "default",
                "username": "nbi",
                "password": "nbi",
                "service": "service",
            },
        )

        # Checking if kafka data is stored
        self.assertEqual(self.harness.charm.state.message_host, "kafka")
        self.assertEqual(self.harness.charm.state.message_port, 9092)

        # Checking if mongodb data is stored
        self.assertEqual(self.harness.charm.state.database_uri, "mongodb://mongo:27017")

        # Checking if prometheus data is stored
        self.assertEqual(self.harness.charm.state.prometheus_host, "prometheus")
        self.assertEqual(self.harness.charm.state.prometheus_port, 9090)

        # Checking if keystone data is stored
        self.assertEqual(self.harness.charm.state.keystone_host, "keystone")
        self.assertEqual(self.harness.charm.state.keystone_port, 5000)
        self.assertEqual(self.harness.charm.state.keystone_user_domain_name, "default")
        self.assertEqual(
            self.harness.charm.state.keystone_project_domain_name, "default"
        )
        self.assertEqual(self.harness.charm.state.keystone_username, "nbi")
        self.assertEqual(self.harness.charm.state.keystone_password, "nbi")
        self.assertEqual(self.harness.charm.state.keystone_service, "service")

        # Verifying status
        self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)

        pod_spec, _ = self.harness.get_pod_spec()

        self.assertDictEqual(expected_result, pod_spec)

    def test_ingress_resources_without_http(self) -> NoReturn:
        """Test ingress resources without HTTP."""
        expected_result = {
            "version": 3,
            "containers": [
                {
                    "name": "nbi",
                    "imageDetails": self.harness.charm.image.fetch(),
                    "imagePullPolicy": "Always",
                    "ports": [
                        {
                            "name": "nbi",
                            "containerPort": 9999,
                            "protocol": "TCP",
                        }
                    ],
                    "envConfig": {
                        "ALLOW_ANONYMOUS_LOGIN": "yes",
                        "OSMNBI_SERVER_ENABLE_TEST": False,
                        "OSMNBI_STATIC_DIR": "/app/osm_nbi/html_public",
                        "OSMNBI_MESSAGE_HOST": "kafka",
                        "OSMNBI_MESSAGE_DRIVER": "kafka",
                        "OSMNBI_MESSAGE_PORT": 9092,
                        "OSMNBI_DATABASE_DRIVER": "mongo",
                        "OSMNBI_DATABASE_URI": "mongodb://mongo:27017",
                        "OSMNBI_DATABASE_COMMONKEY": "osm",
                        "OSMNBI_STORAGE_DRIVER": "mongo",
                        "OSMNBI_STORAGE_PATH": "/app/storage",
                        "OSMNBI_STORAGE_COLLECTION": "files",
                        "OSMNBI_STORAGE_URI": "mongodb://mongo:27017",
                        "OSMNBI_PROMETHEUS_HOST": "prometheus",
                        "OSMNBI_PROMETHEUS_PORT": 9090,
                        "OSMNBI_LOG_LEVEL": "INFO",
                        "OSMNBI_AUTHENTICATION_BACKEND": "internal",
                    },
                }
            ],
            "kubernetesResources": {
                "ingressResources": [],
            },
        }

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

        # Initializing the kafka relation
        kafka_relation_id = self.harness.add_relation("kafka", "kafka")
        self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
        self.harness.update_relation_data(
            kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
        )

        # Initializing the mongodb relation
        mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
        self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
        self.harness.update_relation_data(
            mongodb_relation_id,
            "mongodb/0",
            {"connection_string": "mongodb://mongo:27017"},
        )

        # Initializing the prometheus relation
        promethues_relation_id = self.harness.add_relation("prometheus", "prometheus")
        self.harness.add_relation_unit(promethues_relation_id, "prometheus/0")
        self.harness.update_relation_data(
            promethues_relation_id,
            "prometheus/0",
            {"hostname": "prometheus", "port": 9090},
        )

        self.harness.update_config({"site_url": "nbi"})

        pod_spec, _ = self.harness.get_pod_spec()

        self.assertDictEqual(expected_result, pod_spec)

    def test_ingress_resources_with_http(self) -> NoReturn:
        """Test ingress resources with HTTP."""
        expected_result = {
            "version": 3,
            "containers": [
                {
                    "name": "nbi",
                    "imageDetails": self.harness.charm.image.fetch(),
                    "imagePullPolicy": "Always",
                    "ports": [
                        {
                            "name": "nbi",
                            "containerPort": 9999,
                            "protocol": "TCP",
                        }
                    ],
                    "envConfig": {
                        "ALLOW_ANONYMOUS_LOGIN": "yes",
                        "OSMNBI_SERVER_ENABLE_TEST": False,
                        "OSMNBI_STATIC_DIR": "/app/osm_nbi/html_public",
                        "OSMNBI_MESSAGE_HOST": "kafka",
                        "OSMNBI_MESSAGE_DRIVER": "kafka",
                        "OSMNBI_MESSAGE_PORT": 9092,
                        "OSMNBI_DATABASE_DRIVER": "mongo",
                        "OSMNBI_DATABASE_URI": "mongodb://mongo:27017",
                        "OSMNBI_DATABASE_COMMONKEY": "osm",
                        "OSMNBI_STORAGE_DRIVER": "mongo",
                        "OSMNBI_STORAGE_PATH": "/app/storage",
                        "OSMNBI_STORAGE_COLLECTION": "files",
                        "OSMNBI_STORAGE_URI": "mongodb://mongo:27017",
                        "OSMNBI_PROMETHEUS_HOST": "prometheus",
                        "OSMNBI_PROMETHEUS_PORT": 9090,
                        "OSMNBI_LOG_LEVEL": "INFO",
                        "OSMNBI_AUTHENTICATION_BACKEND": "internal",
                    },
                }
            ],
            "kubernetesResources": {
                "ingressResources": [
                    {
                        "name": "nbi-ingress",
                        "annotations": {
                            "nginx.ingress.kubernetes.io/proxy-body-size": "0",
                            "nginx.ingress.kubernetes.io/ssl-redirect": "false",
                            "nginx.ingress.kubernetes.io/backend-protocol": "HTTPS",
                        },
                        "spec": {
                            "rules": [
                                {
                                    "host": "nbi",
                                    "http": {
                                        "paths": [
                                            {
                                                "path": "/",
                                                "backend": {
                                                    "serviceName": "nbi",
                                                    "servicePort": 9999,
                                                },
                                            }
                                        ]
                                    },
                                }
                            ]
                        },
                    }
                ],
            },
        }

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

        # Initializing the kafka relation
        kafka_relation_id = self.harness.add_relation("kafka", "kafka")
        self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
        self.harness.update_relation_data(
            kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
        )

        # Initializing the mongodb relation
        mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
        self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
        self.harness.update_relation_data(
            mongodb_relation_id,
            "mongodb/0",
            {"connection_string": "mongodb://mongo:27017"},
        )

        # Initializing the prometheus relation
        promethues_relation_id = self.harness.add_relation("prometheus", "prometheus")
        self.harness.add_relation_unit(promethues_relation_id, "prometheus/0")
        self.harness.update_relation_data(
            promethues_relation_id,
            "prometheus/0",
            {"hostname": "prometheus", "port": 9090},
        )

        self.harness.update_config({"site_url": "http://nbi"})

        pod_spec, _ = self.harness.get_pod_spec()

        self.assertDictEqual(expected_result, pod_spec)

    def test_ingress_resources_with_https(self) -> NoReturn:
        """Test ingress resources with HTTPS."""
        expected_result = {
            "version": 3,
            "containers": [
                {
                    "name": "nbi",
                    "imageDetails": self.harness.charm.image.fetch(),
                    "imagePullPolicy": "Always",
                    "ports": [
                        {
                            "name": "nbi",
                            "containerPort": 9999,
                            "protocol": "TCP",
                        }
                    ],
                    "envConfig": {
                        "ALLOW_ANONYMOUS_LOGIN": "yes",
                        "OSMNBI_SERVER_ENABLE_TEST": False,
                        "OSMNBI_STATIC_DIR": "/app/osm_nbi/html_public",
                        "OSMNBI_MESSAGE_HOST": "kafka",
                        "OSMNBI_MESSAGE_DRIVER": "kafka",
                        "OSMNBI_MESSAGE_PORT": 9092,
                        "OSMNBI_DATABASE_DRIVER": "mongo",
                        "OSMNBI_DATABASE_URI": "mongodb://mongo:27017",
                        "OSMNBI_DATABASE_COMMONKEY": "osm",
                        "OSMNBI_STORAGE_DRIVER": "mongo",
                        "OSMNBI_STORAGE_PATH": "/app/storage",
                        "OSMNBI_STORAGE_COLLECTION": "files",
                        "OSMNBI_STORAGE_URI": "mongodb://mongo:27017",
                        "OSMNBI_PROMETHEUS_HOST": "prometheus",
                        "OSMNBI_PROMETHEUS_PORT": 9090,
                        "OSMNBI_LOG_LEVEL": "INFO",
                        "OSMNBI_AUTHENTICATION_BACKEND": "internal",
                    },
                }
            ],
            "kubernetesResources": {
                "ingressResources": [
                    {
                        "name": "nbi-ingress",
                        "annotations": {
                            "nginx.ingress.kubernetes.io/proxy-body-size": "0",
                            "nginx.ingress.kubernetes.io/backend-protocol": "HTTPS",
                        },
                        "spec": {
                            "rules": [
                                {
                                    "host": "nbi",
                                    "http": {
                                        "paths": [
                                            {
                                                "path": "/",
                                                "backend": {
                                                    "serviceName": "nbi",
                                                    "servicePort": 9999,
                                                },
                                            }
                                        ]
                                    },
                                }
                            ],
                            "tls": [{"hosts": ["nbi"], "secretName": "nbi"}],
                        },
                    }
                ],
            },
        }

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

        # Initializing the kafka relation
        kafka_relation_id = self.harness.add_relation("kafka", "kafka")
        self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
        self.harness.update_relation_data(
            kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
        )

        # Initializing the mongodb relation
        mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
        self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
        self.harness.update_relation_data(
            mongodb_relation_id,
            "mongodb/0",
            {"connection_string": "mongodb://mongo:27017"},
        )

        # Initializing the prometheus relation
        promethues_relation_id = self.harness.add_relation("prometheus", "prometheus")
        self.harness.add_relation_unit(promethues_relation_id, "prometheus/0")
        self.harness.update_relation_data(
            promethues_relation_id,
            "prometheus/0",
            {"hostname": "prometheus", "port": 9090},
        )

        self.harness.update_config(
            {"site_url": "https://nbi", "tls_secret_name": "nbi"}
        )

        pod_spec, _ = self.harness.get_pod_spec()

        self.assertDictEqual(expected_result, pod_spec)

    def test_ingress_resources_with_https_and_ingress_whitelist(self) -> NoReturn:
        """Test ingress resources with HTTPS and ingress whitelist."""
        expected_result = {
            "version": 3,
            "containers": [
                {
                    "name": "nbi",
                    "imageDetails": self.harness.charm.image.fetch(),
                    "imagePullPolicy": "Always",
                    "ports": [
                        {
                            "name": "nbi",
                            "containerPort": 9999,
                            "protocol": "TCP",
                        }
                    ],
                    "envConfig": {
                        "ALLOW_ANONYMOUS_LOGIN": "yes",
                        "OSMNBI_SERVER_ENABLE_TEST": False,
                        "OSMNBI_STATIC_DIR": "/app/osm_nbi/html_public",
                        "OSMNBI_MESSAGE_HOST": "kafka",
                        "OSMNBI_MESSAGE_DRIVER": "kafka",
                        "OSMNBI_MESSAGE_PORT": 9092,
                        "OSMNBI_DATABASE_DRIVER": "mongo",
                        "OSMNBI_DATABASE_URI": "mongodb://mongo:27017",
                        "OSMNBI_DATABASE_COMMONKEY": "osm",
                        "OSMNBI_STORAGE_DRIVER": "mongo",
                        "OSMNBI_STORAGE_PATH": "/app/storage",
                        "OSMNBI_STORAGE_COLLECTION": "files",
                        "OSMNBI_STORAGE_URI": "mongodb://mongo:27017",
                        "OSMNBI_PROMETHEUS_HOST": "prometheus",
                        "OSMNBI_PROMETHEUS_PORT": 9090,
                        "OSMNBI_LOG_LEVEL": "INFO",
                        "OSMNBI_AUTHENTICATION_BACKEND": "internal",
                    },
                }
            ],
            "kubernetesResources": {
                "ingressResources": [
                    {
                        "name": "nbi-ingress",
                        "annotations": {
                            "nginx.ingress.kubernetes.io/proxy-body-size": "0",
                            "nginx.ingress.kubernetes.io/backend-protocol": "HTTPS",
                            "nginx.ingress.kubernetes.io/whitelist-source-range": "0.0.0.0/0",
                        },
                        "spec": {
                            "rules": [
                                {
                                    "host": "nbi",
                                    "http": {
                                        "paths": [
                                            {
                                                "path": "/",
                                                "backend": {
                                                    "serviceName": "nbi",
                                                    "servicePort": 9999,
                                                },
                                            }
                                        ]
                                    },
                                }
                            ],
                            "tls": [{"hosts": ["nbi"], "secretName": "nbi"}],
                        },
                    }
                ],
            },
        }

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

        # Initializing the kafka relation
        kafka_relation_id = self.harness.add_relation("kafka", "kafka")
        self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
        self.harness.update_relation_data(
            kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
        )

        # Initializing the mongodb relation
        mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
        self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
        self.harness.update_relation_data(
            mongodb_relation_id,
            "mongodb/0",
            {"connection_string": "mongodb://mongo:27017"},
        )

        # Initializing the prometheus relation
        promethues_relation_id = self.harness.add_relation("prometheus", "prometheus")
        self.harness.add_relation_unit(promethues_relation_id, "prometheus/0")
        self.harness.update_relation_data(
            promethues_relation_id,
            "prometheus/0",
            {"hostname": "prometheus", "port": 9090},
        )

        self.harness.update_config(
            {
                "site_url": "https://nbi",
                "tls_secret_name": "nbi",
                "ingress_whitelist_source_range": "0.0.0.0/0",
            }
        )

        pod_spec, _ = self.harness.get_pod_spec()

        self.assertDictEqual(expected_result, pod_spec)

    def test_on_kafka_unit_relation_changed(self) -> NoReturn:
        """Test to see if kafka relation is updated."""
        self.harness.charm.on.start.emit()

        self.assertIsNone(self.harness.charm.state.message_host)
        self.assertIsNone(self.harness.charm.state.message_port)

        relation_id = self.harness.add_relation("kafka", "kafka")
        self.harness.add_relation_unit(relation_id, "kafka/0")
        self.harness.update_relation_data(
            relation_id, "kafka/0", {"host": "kafka", "port": 9092}
        )

        self.assertEqual(self.harness.charm.state.message_host, "kafka")
        self.assertEqual(self.harness.charm.state.message_port, 9092)

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertNotIn("kafka", self.harness.charm.unit.status.message)
        self.assertIn("mongodb", self.harness.charm.unit.status.message)
        self.assertIn("prometheus", self.harness.charm.unit.status.message)
        self.assertNotIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_on_kafka_app_relation_changed(self) -> NoReturn:
        """Test to see if kafka relation is updated."""
        self.harness.charm.on.start.emit()

        self.assertIsNone(self.harness.charm.state.message_host)
        self.assertIsNone(self.harness.charm.state.message_port)

        relation_id = self.harness.add_relation("kafka", "kafka")
        self.harness.add_relation_unit(relation_id, "kafka/0")
        self.harness.update_relation_data(
            relation_id, "kafka", {"host": "kafka", "port": 9092}
        )

        self.assertEqual(self.harness.charm.state.message_host, "kafka")
        self.assertEqual(self.harness.charm.state.message_port, 9092)

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertNotIn("kafka", self.harness.charm.unit.status.message)
        self.assertIn("mongodb", self.harness.charm.unit.status.message)
        self.assertIn("prometheus", self.harness.charm.unit.status.message)
        self.assertNotIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_on_mongodb_unit_relation_changed(self) -> NoReturn:
        """Test to see if mongodb relation is updated."""
        self.harness.charm.on.start.emit()

        self.assertIsNone(self.harness.charm.state.database_uri)

        relation_id = self.harness.add_relation("mongodb", "mongodb")
        self.harness.add_relation_unit(relation_id, "mongodb/0")
        self.harness.update_relation_data(
            relation_id, "mongodb/0", {"connection_string": "mongodb://mongo:27017"}
        )

        self.assertEqual(self.harness.charm.state.database_uri, "mongodb://mongo:27017")

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertIn("kafka", self.harness.charm.unit.status.message)
        self.assertNotIn("mongodb", self.harness.charm.unit.status.message)
        self.assertIn("prometheus", self.harness.charm.unit.status.message)
        self.assertNotIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_on_mongodb_app_relation_changed(self) -> NoReturn:
        """Test to see if mongodb relation is updated."""
        self.harness.charm.on.start.emit()

        self.assertIsNone(self.harness.charm.state.database_uri)

        relation_id = self.harness.add_relation("mongodb", "mongodb")
        self.harness.add_relation_unit(relation_id, "mongodb/0")
        self.harness.update_relation_data(
            relation_id, "mongodb", {"connection_string": "mongodb://mongo:27017"}
        )

        self.assertEqual(self.harness.charm.state.database_uri, "mongodb://mongo:27017")

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertIn("kafka", self.harness.charm.unit.status.message)
        self.assertNotIn("mongodb", self.harness.charm.unit.status.message)
        self.assertIn("prometheus", self.harness.charm.unit.status.message)
        self.assertNotIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_on_prometheus_unit_relation_changed(self) -> NoReturn:
        """Test to see if prometheus relation is updated."""
        self.harness.charm.on.start.emit()

        self.assertIsNone(self.harness.charm.state.prometheus_host)
        self.assertIsNone(self.harness.charm.state.prometheus_port)

        relation_id = self.harness.add_relation("prometheus", "prometheus")
        self.harness.add_relation_unit(relation_id, "prometheus/0")
        self.harness.update_relation_data(
            relation_id, "prometheus/0", {"hostname": "prometheus", "port": 9090}
        )

        self.assertEqual(self.harness.charm.state.prometheus_host, "prometheus")
        self.assertEqual(self.harness.charm.state.prometheus_port, 9090)

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertIn("kafka", self.harness.charm.unit.status.message)
        self.assertIn("mongodb", self.harness.charm.unit.status.message)
        self.assertNotIn("prometheus", self.harness.charm.unit.status.message)
        self.assertNotIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_on_prometheus_app_relation_changed(self) -> NoReturn:
        """Test to see if prometheus relation is updated."""
        self.harness.charm.on.start.emit()

        self.assertIsNone(self.harness.charm.state.prometheus_host)
        self.assertIsNone(self.harness.charm.state.prometheus_port)

        relation_id = self.harness.add_relation("prometheus", "prometheus")
        self.harness.add_relation_unit(relation_id, "prometheus/0")
        self.harness.update_relation_data(
            relation_id, "prometheus", {"hostname": "prometheus", "port": 9090}
        )

        self.assertEqual(self.harness.charm.state.prometheus_host, "prometheus")
        self.assertEqual(self.harness.charm.state.prometheus_port, 9090)

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertIn("kafka", self.harness.charm.unit.status.message)
        self.assertIn("mongodb", self.harness.charm.unit.status.message)
        self.assertNotIn("prometheus", self.harness.charm.unit.status.message)
        self.assertNotIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_on_keystone_unit_relation_changed(self) -> NoReturn:
        """Test to see if keystone relation is updated."""
        self.harness.update_config({"auth_backend": "keystone"})

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

        self.assertIsNone(self.harness.charm.state.keystone_host)
        self.assertIsNone(self.harness.charm.state.keystone_port)
        self.assertIsNone(self.harness.charm.state.keystone_user_domain_name)
        self.assertIsNone(self.harness.charm.state.keystone_project_domain_name)
        self.assertIsNone(self.harness.charm.state.keystone_username)
        self.assertIsNone(self.harness.charm.state.keystone_password)
        self.assertIsNone(self.harness.charm.state.keystone_service)

        relation_id = self.harness.add_relation("keystone", "keystone")
        self.harness.add_relation_unit(relation_id, "keystone/0")
        self.harness.update_relation_data(
            relation_id,
            "keystone/0",
            {
                "host": "keystone",
                "port": 5000,
                "user_domain_name": "default",
                "project_domain_name": "default",
                "username": "nbi",
                "password": "nbi",
                "service": "service",
            },
        )

        self.assertEqual(self.harness.charm.state.keystone_host, "keystone")
        self.assertEqual(self.harness.charm.state.keystone_port, 5000)
        self.assertEqual(self.harness.charm.state.keystone_user_domain_name, "default")
        self.assertEqual(
            self.harness.charm.state.keystone_project_domain_name, "default"
        )
        self.assertEqual(self.harness.charm.state.keystone_username, "nbi")
        self.assertEqual(self.harness.charm.state.keystone_password, "nbi")
        self.assertEqual(self.harness.charm.state.keystone_service, "service")

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertIn("kafka", self.harness.charm.unit.status.message)
        self.assertIn("mongodb", self.harness.charm.unit.status.message)
        self.assertIn("prometheus", self.harness.charm.unit.status.message)
        self.assertNotIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_on_keystone_app_relation_changed(self) -> NoReturn:
        """Test to see if keystone relation is updated."""
        self.harness.update_config({"auth_backend": "keystone"})

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

        self.assertIsNone(self.harness.charm.state.keystone_host)
        self.assertIsNone(self.harness.charm.state.keystone_port)
        self.assertIsNone(self.harness.charm.state.keystone_user_domain_name)
        self.assertIsNone(self.harness.charm.state.keystone_project_domain_name)
        self.assertIsNone(self.harness.charm.state.keystone_username)
        self.assertIsNone(self.harness.charm.state.keystone_password)
        self.assertIsNone(self.harness.charm.state.keystone_service)

        relation_id = self.harness.add_relation("keystone", "keystone")
        self.harness.add_relation_unit(relation_id, "keystone/0")
        self.harness.update_relation_data(
            relation_id,
            "keystone",
            {
                "host": "keystone",
                "port": 5000,
                "user_domain_name": "default",
                "project_domain_name": "default",
                "username": "nbi",
                "password": "nbi",
                "service": "service",
            },
        )

        self.assertEqual(self.harness.charm.state.keystone_host, "keystone")
        self.assertEqual(self.harness.charm.state.keystone_port, 5000)
        self.assertEqual(self.harness.charm.state.keystone_user_domain_name, "default")
        self.assertEqual(
            self.harness.charm.state.keystone_project_domain_name, "default"
        )
        self.assertEqual(self.harness.charm.state.keystone_username, "nbi")
        self.assertEqual(self.harness.charm.state.keystone_password, "nbi")
        self.assertEqual(self.harness.charm.state.keystone_service, "service")

        # Verifying status
        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)

        # Verifying status message
        self.assertGreater(len(self.harness.charm.unit.status.message), 0)
        self.assertTrue(
            self.harness.charm.unit.status.message.startswith("Waiting for ")
        )
        self.assertIn("kafka", self.harness.charm.unit.status.message)
        self.assertIn("mongodb", self.harness.charm.unit.status.message)
        self.assertIn("prometheus", self.harness.charm.unit.status.message)
        self.assertNotIn("keystone", self.harness.charm.unit.status.message)
        self.assertTrue(self.harness.charm.unit.status.message.endswith(" relations"))

    def test_publish_nbi_info(self) -> NoReturn:
        """Test to see if nbi relation is updated."""
        expected_result = {
            "host": "nbi",
            "port": "9999",
        }

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

        relation_id = self.harness.add_relation("nbi", "ng-ui")
        self.harness.add_relation_unit(relation_id, "ng-ui/0")
        relation_data = self.harness.get_relation_data(relation_id, "nbi")

        self.assertDictEqual(expected_result, relation_data)


if __name__ == "__main__":
    unittest.main()
