# -*- encoding: utf-8 -*-
# Copyright (c) 2019 European Organization for Nuclear Research (CERN)
#
# 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 watcher.common import exception
from watcher.decision_engine.datasources import manager
from watcher.decision_engine.model import model_root
from watcher.decision_engine.strategy import strategies
from watcher.tests import base
from watcher.tests.decision_engine.model import faker_cluster_state


class TestBaseStrategy(base.TestCase):

    def setUp(self):
        super(TestBaseStrategy, self).setUp()

        # fake cluster
        self.fake_c_cluster = faker_cluster_state.FakerModelCollector()

        p_c_model = mock.patch.object(
            strategies.BaseStrategy, "compute_model",
            new_callable=mock.PropertyMock)
        self.m_c_model = p_c_model.start()
        self.addCleanup(p_c_model.stop)

        p_audit_scope = mock.patch.object(
            strategies.BaseStrategy, "audit_scope",
            new_callable=mock.PropertyMock)
        self.m_audit_scope = p_audit_scope.start()
        self.addCleanup(p_audit_scope.stop)

        self.m_audit_scope.return_value = mock.Mock()

        self.m_c_model.return_value = model_root.ModelRoot()
        self.strategy = strategies.DummyStrategy(config=mock.Mock())


class TestBaseStrategyDatasource(TestBaseStrategy):

    def setUp(self):
        super(TestBaseStrategyDatasource, self).setUp()
        self.strategy = strategies.DummyStrategy(
            config=mock.Mock(datasources=None))

    @mock.patch.object(strategies.BaseStrategy, 'osc', None)
    @mock.patch.object(manager, 'DataSourceManager')
    @mock.patch.object(strategies.base, 'CONF')
    def test_global_preference(self, m_conf, m_manager):
        """Test if the global preference is used"""

        m_conf.watcher_datasources.datasources = \
            ['gnocchi', 'monasca', 'ceilometer']

        # Make sure we access the property and not the underlying function.
        m_manager.return_value.get_backend.return_value = \
            mock.NonCallableMock()

        # Access the property so that the configuration is read in order to
        # get the correct datasource
        self.strategy.datasource_backend

        m_manager.assert_called_once_with(
            config=m_conf.watcher_datasources, osc=None)

    @mock.patch.object(strategies.BaseStrategy, 'osc', None)
    @mock.patch.object(manager, 'DataSourceManager')
    @mock.patch.object(strategies.base, 'CONF')
    def test_global_preference_reverse(self, m_conf, m_manager):
        """Test if the global preference is used with another order"""

        m_conf.watcher_datasources.datasources = \
            ['ceilometer', 'monasca', 'gnocchi']

        # Make sure we access the property and not the underlying function.
        m_manager.return_value.get_backend.return_value = \
            mock.NonCallableMock()

        # Access the property so that the configuration is read in order to
        # get the correct datasource
        self.strategy.datasource_backend

        m_manager.assert_called_once_with(
            config=m_conf.watcher_datasources, osc=None)

    @mock.patch.object(strategies.BaseStrategy, 'osc', None)
    @mock.patch.object(manager, 'DataSourceManager')
    @mock.patch.object(strategies.base, 'CONF')
    def test_strategy_preference_override(self, m_conf, m_manager):
        """Test if the global preference can be overridden"""

        datasources = mock.Mock(datasources=['ceilometer'])

        self.strategy = strategies.DummyStrategy(
            config=datasources)

        m_conf.watcher_datasources.datasources = \
            ['ceilometer', 'monasca', 'gnocchi']

        # Access the property so that the configuration is read in order to
        # get the correct datasource
        self.strategy.datasource_backend

        m_manager.assert_called_once_with(
            config=datasources, osc=None)


class TestBaseStrategyException(TestBaseStrategy):

    def setUp(self):
        super(TestBaseStrategyException, self).setUp()

    def test_exception_model(self):
        self.m_c_model.return_value = None
        self.assertRaises(
            exception.ClusterStateNotDefined, self.strategy.execute)

    def test_exception_stale_cdm(self):
        self.fake_c_cluster.set_cluster_data_model_as_stale()
        self.m_c_model.return_value = self.fake_c_cluster.cluster_data_model

        self.assertRaises(
            # TODO(Dantali0n) This should return ClusterStale,
            #  improve set_cluster_data_model_as_stale().
            exception.ClusterStateNotDefined,
            self.strategy.execute)

[((2053, 2108), 'unittest.mock.patch.object', 'mock.patch.object', (['strategies.BaseStrategy', '"""osc"""', 'None'], {}), "(strategies.BaseStrategy, 'osc', None)\n", (2070, 2108), False, 'from unittest import mock\n'), ((2114, 2161), 'unittest.mock.patch.object', 'mock.patch.object', (['manager', '"""DataSourceManager"""'], {}), "(manager, 'DataSourceManager')\n", (2131, 2161), False, 'from unittest import mock\n'), ((2167, 2209), 'unittest.mock.patch.object', 'mock.patch.object', (['strategies.base', '"""CONF"""'], {}), "(strategies.base, 'CONF')\n", (2184, 2209), False, 'from unittest import mock\n'), ((2854, 2909), 'unittest.mock.patch.object', 'mock.patch.object', (['strategies.BaseStrategy', '"""osc"""', 'None'], {}), "(strategies.BaseStrategy, 'osc', None)\n", (2871, 2909), False, 'from unittest import mock\n'), ((2915, 2962), 'unittest.mock.patch.object', 'mock.patch.object', (['manager', '"""DataSourceManager"""'], {}), "(manager, 'DataSourceManager')\n", (2932, 2962), False, 'from unittest import mock\n'), ((2968, 3010), 'unittest.mock.patch.object', 'mock.patch.object', (['strategies.base', '"""CONF"""'], {}), "(strategies.base, 'CONF')\n", (2985, 3010), False, 'from unittest import mock\n'), ((3682, 3737), 'unittest.mock.patch.object', 'mock.patch.object', (['strategies.BaseStrategy', '"""osc"""', 'None'], {}), "(strategies.BaseStrategy, 'osc', None)\n", (3699, 3737), False, 'from unittest import mock\n'), ((3743, 3790), 'unittest.mock.patch.object', 'mock.patch.object', (['manager', '"""DataSourceManager"""'], {}), "(manager, 'DataSourceManager')\n", (3760, 3790), False, 'from unittest import mock\n'), ((3796, 3838), 'unittest.mock.patch.object', 'mock.patch.object', (['strategies.base', '"""CONF"""'], {}), "(strategies.base, 'CONF')\n", (3813, 3838), False, 'from unittest import mock\n'), ((1133, 1174), 'watcher.tests.decision_engine.model.faker_cluster_state.FakerModelCollector', 'faker_cluster_state.FakerModelCollector', ([], {}), '()\n', (1172, 1174), False, 'from watcher.tests.decision_engine.model import faker_cluster_state\n'), ((1196, 1292), 'unittest.mock.patch.object', 'mock.patch.object', (['strategies.BaseStrategy', '"""compute_model"""'], {'new_callable': 'mock.PropertyMock'}), "(strategies.BaseStrategy, 'compute_model', new_callable=\n    mock.PropertyMock)\n", (1213, 1292), False, 'from unittest import mock\n'), ((1421, 1515), 'unittest.mock.patch.object', 'mock.patch.object', (['strategies.BaseStrategy', '"""audit_scope"""'], {'new_callable': 'mock.PropertyMock'}), "(strategies.BaseStrategy, 'audit_scope', new_callable=mock\n    .PropertyMock)\n", (1438, 1515), False, 'from unittest import mock\n'), ((1674, 1685), 'unittest.mock.Mock', 'mock.Mock', ([], {}), '()\n', (1683, 1685), False, 'from unittest import mock\n'), ((1725, 1747), 'watcher.decision_engine.model.model_root.ModelRoot', 'model_root.ModelRoot', ([], {}), '()\n', (1745, 1747), False, 'from watcher.decision_engine.model import model_root\n'), ((2569, 2591), 'unittest.mock.NonCallableMock', 'mock.NonCallableMock', ([], {}), '()\n', (2589, 2591), False, 'from unittest import mock\n'), ((3397, 3419), 'unittest.mock.NonCallableMock', 'mock.NonCallableMock', ([], {}), '()\n', (3417, 3419), False, 'from unittest import mock\n'), ((3992, 4029), 'unittest.mock.Mock', 'mock.Mock', ([], {'datasources': "['ceilometer']"}), "(datasources=['ceilometer'])\n", (4001, 4029), False, 'from unittest import mock\n'), ((4055, 4099), 'watcher.decision_engine.strategy.strategies.DummyStrategy', 'strategies.DummyStrategy', ([], {'config': 'datasources'}), '(config=datasources)\n', (4079, 4099), False, 'from watcher.decision_engine.strategy import strategies\n'), ((1804, 1815), 'unittest.mock.Mock', 'mock.Mock', ([], {}), '()\n', (1813, 1815), False, 'from unittest import mock\n'), ((2018, 2045), 'unittest.mock.Mock', 'mock.Mock', ([], {'datasources': 'None'}), '(datasources=None)\n', (2027, 2045), False, 'from unittest import mock\n')]