#    Copyright 2015 GlobalLogic.  All rights reserved.
#
#    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 tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc

from telemetry_tempest_plugin.aodh.api import base

CONF = config.CONF


class TelemetryAlarmingNegativeGnocchiTest(base.BaseAlarmingTest):
    """Negative tests for show_alarm, update_alarm, show_alarm_history tests

        ** show non-existent alarm
        ** show the deleted alarm
        ** delete deleted alarm
        ** update deleted alarm
    """

    @classmethod
    def skip_checks(cls):
        """This section is used to evaluate config early

        Skip all test methods based on these checks
        """

        super(TelemetryAlarmingNegativeGnocchiTest, cls).skip_checks()
        if not CONF.service_available.gnocchi:
            msg = ("%s: Skipping Gnocchi specific tests without Gnocchi" %
                   cls.__name__)
            raise cls.skipException(msg)

        if 'gnocchi' not in CONF.telemetry_services.metric_backends:
            msg = ("%s: Gnocchi is not one of the configured metric backends" %
                   cls.__name__)
            raise cls.skipException(msg)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('ef45000d-0a72-4781-866d-4cb7bf2582ae')
    def test_get_update_show_history_delete_deleted_alarm(self):
        # get, update and delete the deleted alarm
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule = {'metrics': ["c0d457b6-957e-41de-a384-d5eb0957de3b"],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 100.0,
                'granularity': 90}
        body = self.alarming_client.create_alarm(
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            gnocchi_aggregation_by_metrics_threshold_rule=rule)
        alarm_id = body['alarm_id']
        self.alarming_client.delete_alarm(alarm_id)
        # get the deleted alarm
        self.assertRaises(lib_exc.NotFound, self.alarming_client.show_alarm,
                          alarm_id)

        # update the deleted alarm
        updated_alarm_name = data_utils.rand_name('telemetry_alarm_updated')
        updated_rule = {'metrics': ["c0d457b6-957e-41de-a384-d5eb0957de3b"],
                        'comparison_operator': 'eq',
                        'aggregation_method': 'mean',
                        'threshold': 70,
                        'granularity': 50}
        self.assertRaises(
            lib_exc.NotFound, self.alarming_client.update_alarm,
            alarm_id,
            gnocchi_aggregation_by_metrics_threshold_rule=updated_rule,
            name=updated_alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold')
        # delete the deleted alarm
        self.assertRaises(lib_exc.NotFound, self.alarming_client.delete_alarm,
                          alarm_id)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('3bd874d7-dcbf-410e-ab08-829969282d92')
    def test_create_invalid_alarm_constraint_start(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        tc_name = data_utils.rand_name('time_constraint')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        tc = [{'name': tc_name,
               'start': '11:00am',
               'duration': 10}]
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            time_constraints=tc,
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.skip_because(bug="2045115")
    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('384dec5a-af5b-4a9e-8dc1-9d056fca71d6')
    def test_create_null_alarm_constraint(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        tc = None
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            time_constraints=tc,
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('f358ee93-798e-4641-8fdc-13dc2f7a71c5')
    def test_create_duplicate_alarm_constraint_name(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        tc_name = data_utils.rand_name('time_constraint')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        tc = [{'name': tc_name,
               'start': '* 11 * * *',
               'duration': 10},
              {'name': tc_name,
               'start': '* * * * *',
               'duration': 20}]
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            time_constraints=tc,
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('e1d5d605-61a0-415b-bcaf-dc3a15717344')
    def test_create_invalid_alarm_constraint_timezone(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        tc_name = data_utils.rand_name('time_constraint')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        tc = [{'name': tc_name,
               'start': '* 11 * * *',
               'duration': 10,
               'timezone': 'aaaa'}]
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            time_constraints=tc,
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('7d3ee20c-8a0f-4a43-8a1a-2168da9905da')
    def test_create_invalid_alarm_constraint_duration(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        tc_name = data_utils.rand_name('time_constraint')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        tc = [{'name': tc_name,
               'start': '* 11 * * *',
               'duration': -10}]
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            time_constraints=tc,
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('21ab2919-8680-44d8-be90-57aac5b22474')
    def test_create_invalid_alarm_rule_granularity(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        tc_name = data_utils.rand_name('time_constraint')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0,
                'granularity': -1}
        tc = [{'name': tc_name,
               'start': '* 11 * * *',
               'duration': 10}]
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            time_constraints=tc,
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('b942eeb3-7fc2-4ba4-ad8f-674f3ac7fb96')
    def test_create_invalid_alarm_none_rule(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        tc_name = data_utils.rand_name('time_constraint')
        rule = None
        tc = [{'name': tc_name,
               'start': '* 11 * * *',
               'duration': -10}]
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            time_constraints=tc,
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('a805f2f3-ea3e-4574-b616-3dbe86cb95f8')
    def test_create_invalid_alarm_input_state(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            state='bad_state',
            type='gnocchi_aggregation_by_metrics_threshold',
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('ea90ef4a-135d-48f2-b984-c156a89f627c')
    def test_create_invalid_alarm_input_severity(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            state='ok',
            severity='bad_value',
            type='gnocchi_aggregation_by_metrics_threshold',
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('3af990af-f134-4b87-9234-a25280afc176')
    def test_create_invalid_alarm_input_enabled_string(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            state='ok',
            enabled='bad_value',
            type='gnocchi_aggregation_by_metrics_threshold',
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.skip_because(bug="2045118")
    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('db999b7e-3bc8-4be3-90f3-9d0034f61e8a')
    def test_create_invalid_alarm_input_enabled_int(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            state='ok',
            enabled=0,
            type='gnocchi_aggregation_by_metrics_threshold',
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('0c64f10f-8529-46a5-9172-f0a64789632f')
    def test_create_invalid_alarm_statistic(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'magic',
                'comparison_operator': 'gt',
                'threshold': 2.0}
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('0c421fe7-69e9-4a7c-9df0-547f7bc4c91a')
    def test_create_invalid_alarm_com_op(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'comparison_operator': 'bd_co',
                'threshold': 20.0}
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type='gnocchi_aggregation_by_metrics_threshold',
            gnocchi_aggregation_by_metrics_threshold_rule=rule)

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('5bbccedd-dd80-462c-a6da-d796d7667b5e')
    def test_create_alarm_wsme_workaround(self):
        # create bad time constraint
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule_key = 'gnocchi_aggregation_by_metrics_threshold_rule'
        rules = {
            'type': {
                'name': alarm_name,
                rule_key: {
                    'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                                'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                    'aggregation_method': 'mean',
                    'threshold': 2.0,
                }
            },
            'name': {
                'type': 'gnocchi_aggregation_by_metrics_threshold',
                rule_key: {
                    'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                                'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                    'aggregation_method': 'mean',
                    'threshold': 2.0,
                }
            },
            'threshold_rule/metrics': {
                'name': alarm_name,
                'type': 'gnocchi_aggregation_by_metrics_threshold',
                rule_key: {
                    'aggregation_method': 'mean',
                    'threshold': 2.0,
                }
            },
            'threshold_rule/threshold': {
                'name': alarm_name,
                'type': 'gnocchi_aggregation_by_metrics_threshold',
                rule_key: {
                    'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                                'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                    'aggregation_method': 'mean',
                }
            },
        }

        for field, adef in rules.items():
            self.assertRaises(
                lib_exc.BadRequest,
                self.alarming_client.create_alarm,
                name=getattr(adef, 'name', None),
                type=getattr(adef, 'type', None),
                gnocchi_aggregation_by_metrics_threshold_rule=adef[rule_key]
                )

    def _do_create_alarm_invalid_action(self, ok_actions=None,
                                        alarm_actions=None,
                                        insufficient_data_actions=None,
                                        error_message=None):

        ok_actions = ok_actions or []
        alarm_actions = alarm_actions or []
        insufficient_data_actions = insufficient_data_actions or []
        rule_key = 'gnocchi_aggregation_by_metrics_threshold_rule'
        alarm_name = data_utils.rand_name('telemetry_alarm')
        adef = {
            'enabled': False,
            'state': 'ok',
            'type': 'gnocchi_aggregation_by_metrics_threshold',
            'ok_actions': ok_actions,
            'alarm_actions': alarm_actions,
            'insufficient_data_actions': insufficient_data_actions,
            'repeat_actions': True,
            rule_key: {
                'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'comparison_operator': 'le',
                'aggregation_method': 'count',
                'threshold': 50,
                'evaluation_periods': '3',
                'granularity': '180',
            }
        }
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.create_alarm,
            name=alarm_name,
            type=adef['type'],
            enabled=adef['enabled'],
            state=adef['state'],
            ok_actions=adef['ok_actions'],
            alarm_actions=adef['alarm_actions'],
            insufficient_data_actions=adef['insufficient_data_actions'],
            repeat_actions=adef['repeat_actions'],
            gnocchi_aggregation_by_metrics_threshold_rule=adef[rule_key])

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('95e505c3-51e0-4ac8-8e75-6dfb5828fcd2')
    def test_create_invalid_alarm_ok_actions(self):
        self._do_create_alarm_invalid_action(
            ok_actions=['spam://something/ok'],
            error_message='Unsupported action spam://something/ok')

    @decorators.skip_because(bug="2045116")
    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('4b2b7be0-9d13-4e36-ad28-d11c5aa06411')
    def test_create_invalid_alarm_too_many_actions(self):
        self._do_create_alarm_invalid_action(
            ok_actions=['http://no.where', 'http://no.where2'],
            error_message="alarm_actions count exceeds maximum value 1")

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('2332b637-8193-448c-8b37-e0b6a6fded34')
    def test_post_invalid_alarm_alarm_actions(self):
        self._do_create_alarm_invalid_action(
            alarm_actions=['spam://something/alarm'],
            error_message='Unsupported action spam://something/alarm')

    @decorators.attr(type=['negative'])
    @decorators.idempotent_id('78029ec7-cb70-4f89-a1b6-df235d6688b6')
    def test_post_invalid_alarm_insufficient_data_actions(self):
        self._do_create_alarm_invalid_action(
            insufficient_data_actions=['spam://something/insufficient'],
            error_message='Unsupported action spam://something/insufficient')

    @decorators.attr(type='negative')
    @decorators.idempotent_id('32bbc39e-7423-4309-acf9-39ff584764fc')
    def test_create_update_with_faults_delete_alarm(self):
        # create dual actions
        alarm_name = data_utils.rand_name('telemetry_alarm')
        rule = {'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3',
                            'a1fb80f4-c242-4f57-87c6-68f47521059e'],
                'aggregation_method': 'mean',
                'comparison_operator': 'eq',
                'threshold': 300.0}
        body = self.alarming_client.create_alarm(
            name=alarm_name,
            alarm_actions=['http://no.where'],
            type='gnocchi_aggregation_by_metrics_threshold',
            gnocchi_aggregation_by_metrics_threshold_rule=rule
        )
        alarm_id = body['alarm_id']
        alarms = self.alarming_client.list_alarms(['name', 'eq', alarm_name])
        self.assertEqual(1, len(alarms))

        # update the alarm with wrong fields.
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.update_alarm,
            alarm_id=alarm_id,
            this_can_not_be_correct='ha')

        # update the alarm with invalid action
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.update_alarm,
            alarm_id=alarm_id,
            ok_actions='spam://something/ok')

        # update the alarm with invalid state
        self.assertRaises(
            lib_exc.BadRequest,
            self.alarming_client.alarm_set_state,
            alarm_id=alarm_id,
            state='not valid')

        # Delete alarm and verify if deleted
        self.alarming_client.delete_alarm(alarm_id)
        self.assertRaises(lib_exc.NotFound,
                          self.alarming_client.show_alarm, alarm_id)
