# Copyright (c) 2016 EMC Corporation, Inc.
# 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.

import mock

from cinder import exception
from cinder import test
from cinder.tests.unit.volume.drivers.emc.vnx import fake_storops as storops
from cinder.tests.unit.volume.drivers.emc.vnx import res_mock
from cinder.volume.drivers.emc.vnx import client
from cinder.volume.drivers.emc.vnx import common


class TestExtraSpecs(test.TestCase):
    def test_valid_extra_spec(self):
        extra_spec = {
            'provisioning:type': 'deduplicated',
            'storagetype:tiering': 'nomovement',
        }
        spec_obj = common.ExtraSpecs(extra_spec)
        self.assertEqual(storops.VNXProvisionEnum.DEDUPED,
                         spec_obj.provision)
        self.assertEqual(storops.VNXTieringEnum.NO_MOVE,
                         spec_obj.tier)

    def test_extra_spec_case_insensitive(self):
        extra_spec = {
            'provisioning:type': 'Thin',
            'storagetype:tiering': 'StartHighThenAuto',
        }
        spec_obj = common.ExtraSpecs(extra_spec)
        self.assertEqual(storops.VNXProvisionEnum.THIN,
                         spec_obj.provision)
        self.assertEqual(storops.VNXTieringEnum.HIGH_AUTO,
                         spec_obj.tier)

    def test_empty_extra_spec(self):
        extra_spec = {}
        common.ExtraSpecs.set_defaults(storops.VNXProvisionEnum.THICK,
                                       storops.VNXTieringEnum.HIGH_AUTO)
        spec_obj = common.ExtraSpecs(extra_spec)
        self.assertEqual(storops.VNXProvisionEnum.THICK, spec_obj.provision)
        self.assertEqual(storops.VNXTieringEnum.HIGH_AUTO, spec_obj.tier)

    def test_invalid_provision(self):
        extra_spec = {
            'provisioning:type': 'invalid',
        }
        self.assertRaises(exception.InvalidVolumeType,
                          common.ExtraSpecs,
                          extra_spec)

    def test_invalid_tiering(self):
        extra_spec = {
            'storagetype:tiering': 'invalid',
        }
        self.assertRaises(exception.InvalidVolumeType,
                          common.ExtraSpecs,
                          extra_spec)

    def test_validate_extra_spec_dedup_and_tier_failed(self):
        spec_obj = common.ExtraSpecs({
            'storagetype:pool': 'fake_pool',
            'provisioning:type': 'deduplicated',
            'storagetype:tiering': 'auto',
        })
        enabler_status = common.VNXEnablerStatus(
            dedup=True, fast=True, thin=True)
        self.assertRaises(exception.InvalidVolumeType,
                          spec_obj.validate,
                          enabler_status)

    def test_tier_is_not_set_to_default_for_dedup_provision(self):
        common.ExtraSpecs.set_defaults(storops.VNXProvisionEnum.THICK,
                                       storops.VNXTieringEnum.HIGH_AUTO)
        spec_obj = common.ExtraSpecs({'provisioning:type': 'deduplicated'})
        self.assertEqual(storops.VNXProvisionEnum.DEDUPED, spec_obj.provision)
        self.assertIsNone(spec_obj.tier)

    def test_validate_extra_spec_is_valid(self):
        spec_obj = common.ExtraSpecs({
            'storagetype:pool': 'fake_pool',
            'provisioning:type': 'thin',
            'storagetype:tiering': 'auto',
        })
        enabler_status = common.VNXEnablerStatus(
            dedup=True, fast=True, thin=True)
        re = spec_obj.validate(enabler_status)
        self.assertTrue(re)

    def test_validate_extra_spec_dedup_invalid(self):
        spec_obj = common.ExtraSpecs({
            'provisioning:type': 'deduplicated',
        })
        enabler_status = common.VNXEnablerStatus(dedup=False)
        self.assertRaises(exception.InvalidVolumeType,
                          spec_obj.validate,
                          enabler_status)

    def test_validate_extra_spec_compress_invalid(self):
        spec_obj = common.ExtraSpecs({
            'provisioning:type': 'compressed',
        })
        enabler_status = common.VNXEnablerStatus(compression=False)
        self.assertRaises(exception.InvalidVolumeType,
                          spec_obj.validate,
                          enabler_status)

    def test_validate_extra_spec_no_thin_invalid(self):
        spec_obj = common.ExtraSpecs({
            'provisioning:type': 'compressed',
        })
        enabler_status = common.VNXEnablerStatus(compression=True, thin=False)
        self.assertRaises(exception.InvalidVolumeType,
                          spec_obj.validate,
                          enabler_status)

    def test_validate_extra_spec_tier_invalid(self):
        spec_obj = common.ExtraSpecs({
            'storagetype:tiering': 'auto',
        })
        enabler_status = common.VNXEnablerStatus(
            dedup=True, fast=False, compression=True, snap=True, thin=True)
        self.assertRaises(exception.InvalidVolumeType,