# 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.api.volume import base
from tempest.common.utils import data_utils as utils
from tempest import test


class QosSpecsV2TestJSON(base.BaseVolumeAdminTest):
    """Test the Cinder QoS-specs.

    Tests for  create, list, delete, show, associate,
    disassociate, set/unset key V2 APIs.
    """

    @classmethod
    def resource_setup(cls):
        super(QosSpecsV2TestJSON, cls).resource_setup()
        # Create admin qos client
        # Create a test shared qos-specs for tests
        cls.qos_name = utils.rand_name(cls.__name__ + '-QoS')
        cls.qos_consumer = 'front-end'

        cls.created_qos = cls.create_test_qos_specs(cls.qos_name,
                                                    cls.qos_consumer,
                                                    read_iops_sec='2000')

    def _create_delete_test_qos_with_given_consumer(self, consumer):
        name = utils.rand_name('qos')
        qos = {'name': name, 'consumer': consumer}
        body = self.create_test_qos_specs(name, consumer)
        for key in ['name', 'consumer']:
            self.assertEqual(qos[key], body[key])

        self.volume_qos_client.delete_qos(body['id'])
        self.volume_qos_client.wait_for_resource_deletion(body['id'])

        # validate the deletion
        _, list_qos = self.volume_qos_client.list_qos()
        self.assertNotIn(body, list_qos)

    def _create_test_volume_type(self):
        vol_type_name = utils.rand_name("volume-type")
        _, vol_type = self.volume_types_client.create_volume_type(
            vol_type_name)
        self.addCleanup(self.volume_types_client.delete_volume_type,
                        vol_type['id'])
        return vol_type

    def _test_associate_qos(self, vol_type_id):
        self.volume_qos_client.associate_qos(
            self.created_qos['id'], vol_type_id)

    def _test_get_association_qos(self):
        _, body = self.volume_qos_client.get_association_qos(
            self.created_qos['id'])

        associations = []
        for association in body:
            associations.append(association['id'])

        return associations

    def test_create_delete_qos_with_front_end_consumer(self):
        """Tests the creation and deletion of QoS specs

        With consumer as front end
        """
        self._create_delete_test_qos_with_given_consumer('front-end')

    def test_create_delete_qos_with_back_end_consumer(self):
        """Tests the creation and deletion of QoS specs

        With consumer as back-end
        """
        self._create_delete_test_qos_with_given_consumer('back-end')

    @test.attr(type='smoke')
    def test_create_delete_qos_with_both_consumer(self):
        """Tests the creation and deletion of QoS specs

        With consumer as both front end and back end
        """
        self._create_delete_test_qos_with_given_consumer('both')

    @test.attr(type='smoke')
    def test_get_qos(self):
        """Tests the detail of a given qos-specs"""
        _, body = self.volume_qos_client.get_qos(self.created_qos['id'])
        self.assertEqual(self.qos_name, body['name'])
        self.assertEqual(self.qos_consumer, body['consumer'])

    @test.attr(type='smoke')
    def test_list_qos(self):
        """Tests the list of all qos-specs"""
        _, body = self.volume_qos_client.list_qos()
        self.assertIn(self.created_qos, body)

    @test.attr(type='smoke')
    def test_set_unset_qos_key(self):
        """Test the addition of a specs key to qos-specs"""
        args = {'iops_bytes': '500'}
        _, body = self.volume_qos_client.set_qos_key(self.created_qos['id'],
                                                     iops_bytes='500')
        self.assertEqual(args, body)
        _, body = self.volume_qos_client.get_qos(self.created_qos['id'])
        self.assertEqual(args['iops_bytes'], body['specs']['iops_bytes'])

        # test the deletion of a specs key from qos-specs
        keys = ['iops_bytes']
        self.volume_qos_client.unset_qos_key(self.created_qos['id'], keys)
        operation = 'qos-key-unset'
        self.volume_qos_client.wait_for_qos_operations(self.created_qos['id'],
                                                       operation, keys)
        _, body = self.volume_qos_client.get_qos(self.created_qos['id'])
        self.assertNotIn(keys[0], body['specs'])

    @test.attr(type='smoke')
    def test_associate_disassociate_qos(self):
        """Test the following operations :

        1. associate_qos
        2. get_association_qos
        3. disassociate_qos
        4. disassociate_all_qos
        """

        # create a test volume-type
        vol_type = []
        for _ in range(0, 3):
            vol_type.append(self._create_test_volume_type())

        # associate the qos-specs with volume-types
        for i in range(0, 3):
            self._test_associate_qos(vol_type[i]['id'])

        # get the association of the qos-specs
        associations = self._test_get_association_qos()

        for i in range(0, 3):
            self.assertIn(vol_type[i]['id'], associations)

        # disassociate a volume-type with qos-specs
        self.volume_qos_client.disassociate_qos(
            self.created_qos['id'], vol_type[0]['id'])
        operation = 'disassociate'
        self.volume_qos_client.wait_for_qos_operations(self.created_qos['id'],
                                                       operation,
                                                       vol_type[0]['id'])
        associations = self._test_get_association_qos()
        self.assertNotIn(vol_type[0]['id'], associations)

        # disassociate all volume-types from qos-specs
        self.volume_qos_client.disassociate_all_qos(
            self.created_qos['id'])
        operation = 'disassociate-all'
        self.volume_qos_client.wait_for_qos_operations(self.created_qos['id'],
                                                       operation)
        associations = self._test_get_association_qos()
        self.assertEmpty(associations)


class QosSpecsV1TestJSON(QosSpecsV2TestJSON):
    _api_version = 1
