#!/usr/bin/env python3 # 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 # # 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 MysqldExporterCharm class TestCharm(unittest.TestCase): """Mysql Exporter Charm unit tests.""" def setUp(self) -> NoReturn: """Test setup""" self.harness = Harness(MysqldExporterCharm) 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("mysql", self.harness.charm.unit.status.message) self.assertTrue(self.harness.charm.unit.status.message.endswith(" relation")) def test_on_start_with_relations_without_http(self) -> NoReturn: """Test deployment.""" expected_result = { "version": 3, "containers": [ { "name": "mysqld-exporter", "imageDetails": self.harness.charm.image.fetch(), "imagePullPolicy": "Always", "ports": [ { "name": "mysqld-exporter", "containerPort": 9104, "protocol": "TCP", } ], "envConfig": {"DATA_SOURCE_NAME": "root:rootpw@(mysql:3306)/"}, "kubernetes": { "readinessProbe": { "httpGet": { "path": "/api/health", "port": 9104, }, "initialDelaySeconds": 10, "periodSeconds": 10, "timeoutSeconds": 5, "successThreshold": 1, "failureThreshold": 3, }, "livenessProbe": { "httpGet": { "path": "/api/health", "port": 9104, }, "initialDelaySeconds": 60, "timeoutSeconds": 30, "failureThreshold": 10, }, }, }, ], "kubernetesResources": {"ingressResources": []}, } self.harness.charm.on.start.emit() # Initializing the mysql relation relation_id = self.harness.add_relation("mysql", "mysql") self.harness.add_relation_unit(relation_id, "mysql/0") self.harness.update_relation_data( relation_id, "mysql/0", { "host": "mysql", "port": "3306", "user": "mano", "password": "manopw", "root_password": "rootpw", }, ) # 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_with_http(self) -> NoReturn: """Test ingress resources with HTTP.""" expected_result = { "version": 3, "containers": [ { "name": "mysqld-exporter", "imageDetails": self.harness.charm.image.fetch(), "imagePullPolicy": "Always", "ports": [ { "name": "mysqld-exporter", "containerPort": 9104, "protocol": "TCP", } ], "envConfig": {"DATA_SOURCE_NAME": "root:rootpw@(mysql:3306)/"}, "kubernetes": { "readinessProbe": { "httpGet": { "path": "/api/health", "port": 9104, }, "initialDelaySeconds": 10, "periodSeconds": 10, "timeoutSeconds": 5, "successThreshold": 1, "failureThreshold": 3, }, "livenessProbe": { "httpGet": { "path": "/api/health", "port": 9104, }, "initialDelaySeconds": 60, "timeoutSeconds": 30, "failureThreshold": 10, }, }, }, ], "kubernetesResources": { "ingressResources": [ { "name": "mysqld-exporter-ingress", "annotations": { "nginx.ingress.kubernetes.io/ssl-redirect": "false", }, "spec": { "rules": [ { "host": "mysqld-exporter", "http": { "paths": [ { "path": "/", "backend": { "serviceName": "mysqld-exporter", "servicePort": 9104, }, } ] }, } ] }, } ], }, } self.harness.charm.on.start.emit() # Initializing the mysql relation relation_id = self.harness.add_relation("mysql", "mysql") self.harness.add_relation_unit(relation_id, "mysql/0") self.harness.update_relation_data( relation_id, "mysql/0", { "host": "mysql", "port": "3306", "user": "mano", "password": "manopw", "root_password": "rootpw", }, ) self.harness.update_config({"site_url": "http://mysqld-exporter"}) 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": "mysqld-exporter", "imageDetails": self.harness.charm.image.fetch(), "imagePullPolicy": "Always", "ports": [ { "name": "mysqld-exporter", "containerPort": 9104, "protocol": "TCP", } ], "envConfig": {"DATA_SOURCE_NAME": "root:rootpw@(mysql:3306)/"}, "kubernetes": { "readinessProbe": { "httpGet": { "path": "/api/health", "port": 9104, }, "initialDelaySeconds": 10, "periodSeconds": 10, "timeoutSeconds": 5, "successThreshold": 1, "failureThreshold": 3, }, "livenessProbe": { "httpGet": { "path": "/api/health", "port": 9104, }, "initialDelaySeconds": 60, "timeoutSeconds": 30, "failureThreshold": 10, }, }, }, ], "kubernetesResources": { "ingressResources": [ { "name": "mysqld-exporter-ingress", "annotations": {}, "spec": { "rules": [ { "host": "mysqld-exporter", "http": { "paths": [ { "path": "/", "backend": { "serviceName": "mysqld-exporter", "servicePort": 9104, }, } ] }, } ], "tls": [ { "hosts": ["mysqld-exporter"], "secretName": "mysqld-exporter", } ], }, } ], }, } self.harness.charm.on.start.emit() # Initializing the mysql relation relation_id = self.harness.add_relation("mysql", "mysql") self.harness.add_relation_unit(relation_id, "mysql/0") self.harness.update_relation_data( relation_id, "mysql/0", { "host": "mysql", "port": "3306", "user": "mano", "password": "manopw", "root_password": "rootpw", }, ) self.harness.update_config( { "site_url": "https://mysqld-exporter", "tls_secret_name": "mysqld-exporter", } ) 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": "mysqld-exporter", "imageDetails": self.harness.charm.image.fetch(), "imagePullPolicy": "Always", "ports": [ { "name": "mysqld-exporter", "containerPort": 9104, "protocol": "TCP", } ], "envConfig": {"DATA_SOURCE_NAME": "root:rootpw@(mysql:3306)/"}, "kubernetes": { "readinessProbe": { "httpGet": { "path": "/api/health", "port": 9104, }, "initialDelaySeconds": 10, "periodSeconds": 10, "timeoutSeconds": 5, "successThreshold": 1, "failureThreshold": 3, }, "livenessProbe": { "httpGet": { "path": "/api/health", "port": 9104, }, "initialDelaySeconds": 60, "timeoutSeconds": 30, "failureThreshold": 10, }, }, }, ], "kubernetesResources": { "ingressResources": [ { "name": "mysqld-exporter-ingress", "annotations": { "nginx.ingress.kubernetes.io/whitelist-source-range": "0.0.0.0/0", }, "spec": { "rules": [ { "host": "mysqld-exporter", "http": { "paths": [ { "path": "/", "backend": { "serviceName": "mysqld-exporter", "servicePort": 9104, }, } ] }, } ], "tls": [ { "hosts": ["mysqld-exporter"], "secretName": "mysqld-exporter", } ], }, } ], }, } self.harness.charm.on.start.emit() # Initializing the mysql relation relation_id = self.harness.add_relation("mysql", "mysql") self.harness.add_relation_unit(relation_id, "mysql/0") self.harness.update_relation_data( relation_id, "mysql/0", { "host": "mysql", "port": "3306", "user": "mano", "password": "manopw", "root_password": "rootpw", }, ) self.harness.update_config( { "site_url": "https://mysqld-exporter", "tls_secret_name": "mysqld-exporter", "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_mysql_unit_relation_changed(self) -> NoReturn: """Test to see if mysql relation is updated.""" self.harness.charm.on.start.emit() relation_id = self.harness.add_relation("mysql", "mysql") self.harness.add_relation_unit(relation_id, "mysql/0") self.harness.update_relation_data( relation_id, "mysql/0", { "host": "mysql", "port": "3306", "user": "mano", "password": "manopw", "root_password": "rootpw", }, ) # Verifying status self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus) def test_publish_target_info(self) -> NoReturn: """Test to see if target relation is updated.""" expected_result = { "hostname": "mysqld-exporter", "port": "9104", "metrics_path": "/metrics", "scrape_interval": "30s", "scrape_timeout": "15s", } self.harness.charm.on.start.emit() relation_id = self.harness.add_relation("prometheus-scrape", "prometheus") self.harness.add_relation_unit(relation_id, "prometheus/0") relation_data = self.harness.get_relation_data(relation_id, "mysqld-exporter/0") self.assertDictEqual(expected_result, relation_data) def test_publish_scrape_info_with_site_url(self) -> NoReturn: """Test to see if target relation is updated.""" expected_result = { "hostname": "mysqld-exporter-osm", "port": "80", "metrics_path": "/metrics", "scrape_interval": "30s", "scrape_timeout": "15s", } self.harness.charm.on.start.emit() self.harness.update_config({"site_url": "http://mysqld-exporter-osm"}) relation_id = self.harness.add_relation("prometheus-scrape", "prometheus") self.harness.add_relation_unit(relation_id, "prometheus/0") relation_data = self.harness.get_relation_data(relation_id, "mysqld-exporter/0") self.assertDictEqual(expected_result, relation_data) def test_publish_dashboard_info(self) -> NoReturn: """Test to see if dashboard relation is updated.""" self.harness.charm.on.start.emit() relation_id = self.harness.add_relation("grafana-dashboard", "grafana") self.harness.add_relation_unit(relation_id, "grafana/0") relation_data = self.harness.get_relation_data(relation_id, "mysqld-exporter/0") self.assertTrue("dashboard" in relation_data) self.assertTrue(len(relation_data["dashboard"]) > 0) self.assertEqual(relation_data["name"], "osm-mysql") if __name__ == "__main__": unittest.main()