text: # -*- encoding: utf-8 -*-
  # Copyright (c) 2019 European Organization for Nuclear Research (CERN)
  #
  # Authors: Corne Lukken <info@dantalion.nl>
  #
  # 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.
  
  from unittest import mock
  
  from oslo_config import cfg
  from oslo_log import log
  
  from watcher.common import clients
  from watcher.common import exception
  from watcher.decision_engine.datasources import grafana
  from watcher.tests import base
  
  from http import HTTPStatus
  import requests
  
  CONF = cfg.CONF
  LOG = log.getLogger(__name__)
  
  
  @mock.patch.object(clients.OpenStackClients, 'nova', mock.Mock())
  class TestGrafana(base.BaseTestCase):
      """Test the GrafanaHelper datasource
  
      Objects under test are preceded with t_ and mocked objects are preceded
      with m_ , additionally, patched objects are preceded with p_ no object
      under test should be created in setUp this can influence the results.
      """
  
      def setUp(self):
          super(TestGrafana, self).setUp()
  
          self.p_conf = mock.patch.object(
              grafana, 'CONF',
              new_callable=mock.PropertyMock)
          self.m_conf = self.p_conf.start()
          self.addCleanup(self.p_conf.stop)
  
          self.m_conf.grafana_client.token = \
              "eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk=="
          self.m_conf.grafana_client.base_url = "https://grafana.proxy/api/"
          self.m_conf.grafana_client.project_id_map = {'host_cpu_usage': 7221}
          self.m_conf.grafana_client.database_map = \
              {'host_cpu_usage': 'mock_db'}
          self.m_conf.grafana_client.attribute_map = \
              {'host_cpu_usage': 'hostname'}
          self.m_conf.grafana_client.translator_map = \
              {'host_cpu_usage': 'influxdb'}
          self.m_conf.grafana_client.query_map = \
              {'host_cpu_usage': 'SELECT 100-{0}("{0}_value") FROM {3}.'
                                 'cpu_percent WHERE ("host" =~ /^{1}$/ AND '
                                 '"type_instance" =~/^idle$/ AND time > '
                                 '(now()-{2}m)'}
  
          self.m_grafana = grafana.GrafanaHelper(osc=mock.Mock())
          stat_agg_patcher = mock.patch.object(
              self.m_grafana, 'statistic_aggregation',
              spec=grafana.GrafanaHelper.statistic_aggregation)
          self.mock_aggregation = stat_agg_patcher.start()
          self.addCleanup(stat_agg_patcher.stop)
  
          self.m_compute_node = mock.Mock(
              id='16a86790-327a-45f9-bc82-45839f062fdc',
              hostname='example.hostname.ch'
          )
          self.m_instance = mock.Mock(
              id='73b1ff78-aca7-404f-ac43-3ed16c1fa555',
              human_id='example.hostname'
          )
  
      def test_configured(self):
          """Initialize GrafanaHelper and check if configured is true"""
  
          t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
          self.assertTrue(t_grafana.configured)
  
      def test_configured_error(self):
          """Butcher the required configuration and test if configured is false
  
          """
  
          self.m_conf.grafana_client.base_url = ""
          t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
          self.assertFalse(t_grafana.configured)
  
      def test_configured_raise_error(self):
          """Test raising error when using improperly configured GrafanHelper
  
          Assure that the _get_metric method raises errors if the metric is
          missing from the map
          """
  
          # Clear the METRIC_MAP of Grafana since it is a static variable that
          # other tests might have set before this test runs.
          grafana.GrafanaHelper.METRIC_MAP = {}
  
          self.m_conf.grafana_client.base_url = ""
  
          t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
  
          self.assertFalse(t_grafana.configured)
          self.assertEqual({}, t_grafana.METRIC_MAP)
          self.assertRaises(
              exception.MetricNotAvailable,
              t_grafana.get_host_cpu_usage,
              self.m_compute_node
          )
  
      @mock.patch.object(requests, 'get')
      def test_request_raise_error(self, m_request):
          """Test raising error when status code of request indicates problem
  
          Assure that the _request method raises errors if the response indicates
          problems.
          """
  
          m_request.return_value = mock.Mock(status_code=HTTPStatus.NOT_FOUND)
  
          t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
  
          self.assertIsNone(t_grafana.get_host_cpu_usage(self.m_compute_node))
  
      def test_no_metric_raise_error(self):
          """Test raising error when specified meter does not exist"""
  
          t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
  
          self.assertRaises(exception.MetricNotAvailable,
                            t_grafana.statistic_aggregation,
                            self.m_compute_node,
                            'none existing meter', 60)
  
      @mock.patch.object(grafana.GrafanaHelper, '_request')
      def test_get_metric_raise_error(self, m_request):
          """Test raising error when endpoint unable to deliver data for metric
  
          """
  
          m_request.return_value.content = "{}"
  
          t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
  
          self.assertRaises(exception.NoSuchMetricForHost,
                            t_grafana.get_host_cpu_usage,
                            self.m_compute_node, 60)
  
      def test_metric_builder(self):
          """Creates valid and invalid sets of configuration for metrics
  
          Ensures that a valid metric entry can be configured even if multiple
          invalid configurations exist for other metrics.
          """
  
          self.m_conf.grafana_client.project_id_map = {
              'host_cpu_usage': 7221,
              'host_ram_usage': 7221,
              'instance_ram_allocated': 7221,
          }
          self.m_conf.grafana_client.database_map = {
              'host_cpu_usage': 'mock_db',
              'instance_cpu_usage': 'mock_db',
              'instance_ram_allocated': 'mock_db',
          }
          self.m_conf.grafana_client.attribute_map = {
              'host_cpu_usage': 'hostname',
              'host_power': 'hostname',
              'instance_ram_allocated': 'human_id',
          }
          self.m_conf.grafana_client.translator_map = {
              'host_cpu_usage': 'influxdb',
              'host_inlet_temp': 'influxdb',
              # validate that invalid entries don't get added
              'instance_ram_usage': 'dummy',
              'instance_ram_allocated': 'influxdb',
          }
          self.m_conf.grafana_client.query_map = {
              'host_cpu_usage': 'SHOW SERIES',
              'instance_ram_usage': 'SHOW SERIES',
              'instance_ram_allocated': 'SHOW SERIES',
          }
  
          expected_result = {
              'host_cpu_usage': {
                  'db': 'mock_db',
                  'project': 7221,
                  'attribute': 'hostname',
                  'translator': 'influxdb',
                  'query': 'SHOW SERIES'},
              'instance_ram_allocated': {
                  'db': 'mock_db',
                  'project': 7221,
                  'attribute': 'human_id',
                  'translator': 'influxdb',
                  'query': 'SHOW SERIES'},
          }
  
          t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
          self.assertEqual(t_grafana.METRIC_MAP, expected_result)
  
      @mock.patch.object(grafana.GrafanaHelper, '_request')
      def test_statistic_aggregation(self, m_request):
          m_request.return_value.content = "{ \"results\": [{ \"series\": [{ " \
                                           "\"columns\": [\"time\",\"mean\"]," \
                                           "\"values\": [[1552500855000, " \
                                           "67.3550078657577]]}]}]}"
  
          t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
  
          result = t_grafana.statistic_aggregation(
              self.m_compute_node, 'compute_node', 'host_cpu_usage', 60)
          self.assertEqual(result, 67.3550078657577)
  
      def test_get_host_cpu_usage(self):
          self.m_grafana.get_host_cpu_usage(self.m_compute_node, 60, 'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'compute_node', 'host_cpu_usage', 60, 'min',
              15)
  
      def test_get_host_ram_usage(self):
          self.m_grafana.get_host_ram_usage(self.m_compute_node, 60,
                                            'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'compute_node', 'host_ram_usage', 60, 'min',
              15)
  
      def test_get_host_outlet_temperature(self):
          self.m_grafana.get_host_outlet_temp(self.m_compute_node, 60,
                                              'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'compute_node', 'host_outlet_temp', 60, 'min',
              15)
  
      def test_get_host_inlet_temperature(self):
          self.m_grafana.get_host_inlet_temp(self.m_compute_node, 60,
                                             'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'compute_node', 'host_inlet_temp', 60, 'min',
              15)
  
      def test_get_host_airflow(self):
          self.m_grafana.get_host_airflow(self.m_compute_node, 60,
                                          'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'compute_node', 'host_airflow', 60, 'min',
              15)
  
      def test_get_host_power(self):
          self.m_grafana.get_host_power(self.m_compute_node, 60,
                                        'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'compute_node', 'host_power', 60, 'min',
              15)
  
      def test_get_instance_cpu_usage(self):
          self.m_grafana.get_instance_cpu_usage(self.m_compute_node, 60,
                                                'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'instance', 'instance_cpu_usage', 60,
              'min', 15)
  
      def test_get_instance_ram_usage(self):
          self.m_grafana.get_instance_ram_usage(self.m_compute_node, 60,
                                                'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'instance', 'instance_ram_usage', 60,
              'min', 15)
  
      def test_get_instance_ram_allocated(self):
          self.m_grafana.get_instance_ram_allocated(self.m_compute_node, 60,
                                                    'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'instance', 'instance_ram_allocated', 60,
              'min', 15)
  
      def test_get_instance_l3_cache_usage(self):
          self.m_grafana.get_instance_l3_cache_usage(self.m_compute_node, 60,
                                                     'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'instance', 'instance_l3_cache_usage', 60,
              'min', 15)
  
      def test_get_instance_root_disk_allocated(self):
          self.m_grafana.get_instance_root_disk_size(self.m_compute_node, 60,
                                                     'min', 15)
          self.mock_aggregation.assert_called_once_with(
              self.m_compute_node, 'instance', 'instance_root_disk_size', 60,
              'min', 15)
  