# -*- 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)

[((60, 5, 60, 60), 'unittest.mock.patch.object', 'mock.patch.object', ({(60, 23, 60, 46): 'strategies.BaseStrategy', (60, 48, 60, 53): '"""osc"""', (60, 55, 60, 59): 'None'}, {}), "(strategies.BaseStrategy, 'osc', None)", False, 'from unittest import mock\n'), ((61, 5, 61, 52), 'unittest.mock.patch.object', 'mock.patch.object', ({(61, 23, 61, 30): 'manager', (61, 32, 61, 51): '"""DataSourceManager"""'}, {}), "(manager, 'DataSourceManager')", False, 'from unittest import mock\n'), ((62, 5, 62, 47), 'unittest.mock.patch.object', 'mock.patch.object', ({(62, 23, 62, 38): 'strategies.base', (62, 40, 62, 46): '"""CONF"""'}, {}), "(strategies.base, 'CONF')", False, 'from unittest import mock\n'), ((80, 5, 80, 60), 'unittest.mock.patch.object', 'mock.patch.object', ({(80, 23, 80, 46): 'strategies.BaseStrategy', (80, 48, 80, 53): '"""osc"""', (80, 55, 80, 59): 'None'}, {}), "(strategies.BaseStrategy, 'osc', None)", False, 'from unittest import mock\n'), ((81, 5, 81, 52), 'unittest.mock.patch.object', 'mock.patch.object', ({(81, 23, 81, 30): 'manager', (81, 32, 81, 51): '"""DataSourceManager"""'}, {}), "(manager, 'DataSourceManager')", False, 'from unittest import mock\n'), ((82, 5, 82, 47), 'unittest.mock.patch.object', 'mock.patch.object', ({(82, 23, 82, 38): 'strategies.base', (82, 40, 82, 46): '"""CONF"""'}, {}), "(strategies.base, 'CONF')", False, 'from unittest import mock\n'), ((100, 5, 100, 60), 'unittest.mock.patch.object', 'mock.patch.object', ({(100, 23, 100, 46): 'strategies.BaseStrategy', (100, 48, 100, 53): '"""osc"""', (100, 55, 100, 59): 'None'}, {}), "(strategies.BaseStrategy, 'osc', None)", False, 'from unittest import mock\n'), ((101, 5, 101, 52), 'unittest.mock.patch.object', 'mock.patch.object', ({(101, 23, 101, 30): 'manager', (101, 32, 101, 51): '"""DataSourceManager"""'}, {}), "(manager, 'DataSourceManager')", False, 'from unittest import mock\n'), ((102, 5, 102, 47), 'unittest.mock.patch.object', 'mock.patch.object', ({(102, 23, 102, 38): 'strategies.base', (102, 40, 102, 46): '"""CONF"""'}, {}), "(strategies.base, 'CONF')", False, 'from unittest import mock\n'), ((33, 30, 33, 71), 'watcher.tests.decision_engine.model.faker_cluster_state.FakerModelCollector', 'faker_cluster_state.FakerModelCollector', ({}, {}), '()', False, 'from watcher.tests.decision_engine.model import faker_cluster_state\n'), ((35, 20, 37, 43), 'unittest.mock.patch.object', 'mock.patch.object', (), '', False, 'from unittest import mock\n'), ((41, 24, 43, 43), 'unittest.mock.patch.object', 'mock.patch.object', (), '', False, 'from unittest import mock\n'), ((47, 42, 47, 53), 'unittest.mock.Mock', 'mock.Mock', ({}, {}), '()', False, 'from unittest import mock\n'), ((49, 38, 49, 60), 'watcher.decision_engine.model.model_root.ModelRoot', 'model_root.ModelRoot', ({}, {}), '()', False, 'from watcher.decision_engine.model import model_root\n'), ((71, 12, 71, 34), 'unittest.mock.NonCallableMock', 'mock.NonCallableMock', ({}, {}), '()', False, 'from unittest import mock\n'), ((91, 12, 91, 34), 'unittest.mock.NonCallableMock', 'mock.NonCallableMock', ({}, {}), '()', False, 'from unittest import mock\n'), ((106, 22, 106, 59), 'unittest.mock.Mock', 'mock.Mock', (), '', False, 'from unittest import mock\n'), ((108, 24, 109, 31), 'watcher.decision_engine.strategy.strategies.DummyStrategy', 'strategies.DummyStrategy', (), '', False, 'from watcher.decision_engine.strategy import strategies\n'), ((50, 56, 50, 67), 'unittest.mock.Mock', 'mock.Mock', ({}, {}), '()', False, 'from unittest import mock\n'), ((58, 19, 58, 46), 'unittest.mock.Mock', 'mock.Mock', (), '', False, 'from unittest import mock\n')]