# Copyright (c) 2014 ProphetStor, 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 copy
import errno
import httplib
import re

import mock
from oslo_utils import units

from cinder import exception
from cinder import test
from cinder.volume import configuration as conf
from cinder.volume.drivers.prophetstor import dpl_iscsi as DPLDRIVER
from cinder.volume.drivers.prophetstor import dplcommon as DPLCOMMON

POOLUUID = 'ac33fc6e417440d5a1ef27d7231e1cc4'
VOLUMEUUID = 'a000000000000000000000000000001'
INITIATOR = 'iqn.2013-08.org.debian:01:aaaaaaaa'
DATA_IN_VOLUME = {'id': VOLUMEUUID}
DATA_IN_CONNECTOR = {'initiator': INITIATOR}
DATA_SERVER_INFO = 0, {
    'metadata': {'vendor': 'ProphetStor',
                 'version': '1.5'}}

DATA_POOLS = 0, {
    'children': [POOLUUID]
}

DATA_POOLINFO = 0, {
    'capabilitiesURI': '',
    'children': [],
    'childrenrange': '',
    'completionStatus': 'Complete',
    'metadata': {'available_capacity': 4294967296,
                 'ctime': 1390551362349,
                 'vendor': 'prophetstor',
                 'version': '1.5',
                 'display_description': 'Default Pool',
                 'display_name': 'default_pool',
                 'event_uuid': '4f7c4d679a664857afa4d51f282a516a',
                 'physical_device': {'cache': [],
                                     'data': ['disk_uuid_0',
                                              'disk_uuid_1',
                                              'disk_uuid_2'],
                                     'log': [],
                                     'spare': []},
                 'pool_uuid': POOLUUID,
                 'properties': {'raid_level': 'raid0'},
                 'state': 'Online',
                 'used_capacity': 0,
                 'total_capacity': 4294967296,
                 'zpool_guid': '8173612007304181810'},
    'objectType': 'application/cdmi-container',
    'percentComplete': 100}

DATA_ASSIGNVDEV = 0, {
    'children': [],
    'childrenrange': '',
    'completionStatus': 'Complete',
    'domainURI': '',
    'exports': {'Network/iSCSI': [
                {'logical_unit_name': '',
                 'logical_unit_number': '101',
                 'permissions': [INITIATOR],
                 'portals': ['172.31.1.210:3260'],
                 'target_identifier':
                 'iqn.2013-09.com.prophetstor:hypervisor.886423051816'
                 }]},
    'metadata': {'ctime': 0,
                 'event_uuid': 'c11e90287e9348d0b4889695f1ec4be5',
                 'type': 'volume'},
    'objectID': '',
    'objectName': 'd827e23d403f4f12bb208a6fec208fd8',
    'objectType': 'application/cdmi-container',
    'parentID': '8daa374670af447e8efea27e16bf84cd',
    'parentURI': '/dpl_volume',
    'snapshots': []
}

DATA_OUTPUT = 0, None

MOD_OUTPUT = {'status': 'available'}

DATA_IN_GROUP = {'id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
                 'name': 'group123',
                 'description': 'des123',
                 'status': ''}

DATA_IN_VOLUME = {'id': 'abc123',
                  'display_name': 'abc123',
                  'display_description': '',
                  'size': 1,
                  'host': "hostname@backend#%s" % POOLUUID}

DATA_IN_VOLUME_VG = {'id': 'abc123',
                     'display_name': 'abc123',
                     'display_description': '',
                     'size': 1,
                     'consistencygroup_id':
                         'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
                     'status': 'available',
                     'host': "hostname@backend#%s" % POOLUUID}

DATA_IN_VOLUME1 = {'id': 'abc456',
                   'display_name': 'abc456',
                   'display_description': '',
                   'size': 1,
                   'host': "hostname@backend#%s" % POOLUUID}

DATA_IN_CG_SNAPSHOT = {
    'consistencygroup_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
    'id': 'cgsnapshot1',
    'name': 'cgsnapshot1',
    'description': 'cgsnapshot1',
    'status': ''}

DATA_IN_SNAPSHOT = {'id': 'snapshot1',
                    'volume_id': 'abc123',
                    'display_name': 'snapshot1',
                    'display_description': ''}

DATA_OUT_SNAPSHOT_CG = {
    'id': 'snapshot1',
    'volume_id': 'abc123',
    'display_name': 'snapshot1',
    'display_description': '',
    'cgsnapshot_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee'}


class TestProphetStorDPLVolume(test.TestCase):

    def _gen_snapshot_url(self, vdevid, snapshotid):
        snapshot_url = '/%s/%s/%s' % (vdevid, DPLCOMMON.DPL_OBJ_SNAPSHOT,
                                      snapshotid)
        return snapshot_url

    def setUp(self):
        super(TestProphetStorDPLVolume, self).setUp()
        self.dplcmd = DPLCOMMON.DPLVolume('1.1.1.1', 8356, 'admin', 'password')
        self.DPL_MOCK = mock.MagicMock()
        self.dplcmd.objCmd = self.DPL_MOCK
        self.DPL_MOCK.send_cmd.return_value = DATA_OUTPUT

    def test_getserverinfo(self):
        self.dplcmd.get_server_info()
        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'GET',
            '/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_SYSTEM),
            None,
            [httplib.OK, httplib.ACCEPTED])

    def test_createvdev(self):
        self.dplcmd.create_vdev(DATA_IN_VOLUME['id'],
                                DATA_IN_VOLUME['display_name'],
                                DATA_IN_VOLUME['display_description'],
                                POOLUUID,
                                int(DATA_IN_VOLUME['size']) * units.Gi)

        metadata = {}
        metadata['display_name'] = DATA_IN_VOLUME['display_name']
        metadata['display_description'] = DATA_IN_VOLUME['display_description']
        metadata['pool_uuid'] = POOLUUID
        metadata['total_capacity'] = int(DATA_IN_VOLUME['size']) * units.Gi
        metadata['maximum_snapshot'] = 1024
        metadata['properties'] = dict(thin_provision=True)
        params = {}
        params['metadata'] = metadata
        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'PUT',
            '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME,
                            DATA_IN_VOLUME['id']),
            params,
            [httplib.OK, httplib.ACCEPTED, httplib.CREATED])

    def test_extendvdev(self):
        self.dplcmd.extend_vdev(DATA_IN_VOLUME['id'],
                                DATA_IN_VOLUME['display_name'],
                                DATA_IN_VOLUME['display_description'],
                                int(DATA_IN_VOLUME['size']) * units.Gi)
        metadata = {}
        metadata['display_name'] = DATA_IN_VOLUME['display_name']
        metadata['display_description'] = DATA_IN_VOLUME['display_description']
        metadata['total_capacity'] = int(DATA_IN_VOLUME['size']) * units.Gi
        metadata['maximum_snapshot'] = 1024
        params = {}
        params['metadata'] = metadata
        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'PUT',
            '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME,
                            DATA_IN_VOLUME['id']),
            params,
            [httplib.OK, httplib.ACCEPTED, httplib.CREATED])

    def test_deletevdev(self):
        self.dplcmd.delete_vdev(DATA_IN_VOLUME['id'], True)
        metadata = {}
        params = {}
        metadata['force'] = True
        params['metadata'] = metadata
        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'DELETE',
            '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME,
                            DATA_IN_VOLUME['id']),
            params,
            [httplib.OK, httplib.ACCEPTED, httplib.NOT_FOUND,
             httplib.NO_CONTENT])

    def test_createvdevfromsnapshot(self):
        self.dplcmd.create_vdev_from_snapshot(
            DATA_IN_VOLUME['id'],
            DATA_IN_VOLUME['display_name'],
            DATA_IN_VOLUME['display_description'],
            DATA_IN_SNAPSHOT['id'],
            POOLUUID)
        metadata = {}
        params = {}
        metadata['snapshot_operation'] = 'copy'
        metadata['display_name'] = DATA_IN_VOLUME['display_name']
        metadata['display_description'] = DATA_IN_VOLUME['display_description']
        metadata['pool_uuid'] = POOLUUID
        metadata['maximum_snapshot'] = 1024
        metadata['properties'] = dict(thin_provision=True)
        params['metadata'] = metadata
        params['copy'] = self._gen_snapshot_url(DATA_IN_VOLUME['id'],
                                                DATA_IN_SNAPSHOT['id'])
        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'PUT',
            '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME,
                            DATA_IN_VOLUME['id']),
            params,
            [httplib.OK, httplib.ACCEPTED, httplib.CREATED])

    def test_getpool(self):
        self.dplcmd.get_pool(POOLUUID)
        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'GET',
            '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_POOL,
                            POOLUUID),
            None,
            [httplib.OK, httplib.ACCEPTED])

    def test_clonevdev(self):
        self.dplcmd.clone_vdev(
            DATA_IN_VOLUME['id'],
            DATA_IN_VOLUME1['id'],
            POOLUUID,
            DATA_IN_VOLUME['display_name'],
            DATA_IN_VOLUME['display_description'],
            int(DATA_IN_VOLUME['size']) * units.Gi
        )
        metadata = {}
        params = {}
        metadata["snapshot_operation"] = "clone"
        metadata["display_name"] = DATA_IN_VOLUME['display_name']
        metadata["display_description"] = DATA_IN_VOLUME['display_description']
        metadata["pool_uuid"] = POOLUUID
        metadata["total_capacity"] = int(DATA_IN_VOLUME['size']) * units.Gi
        metadata['maximum_snapshot'] = 1024
        metadata['properties'] = dict(thin_provision=True)
        params["metadata"] = metadata
        params["copy"] = DATA_IN_VOLUME['id']

        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'PUT',
            '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME,
                            DATA_IN_VOLUME1['id']),
            params,
            [httplib.OK, httplib.CREATED, httplib.ACCEPTED])

    def test_createvdevsnapshot(self):
        self.dplcmd.create_vdev_snapshot(
            DATA_IN_VOLUME['id'],
            DATA_IN_SNAPSHOT['id'],
            DATA_IN_SNAPSHOT['display_name'],
            DATA_IN_SNAPSHOT['display_description']
        )
        metadata = {}
        params = {}
        metadata['display_name'] = DATA_IN_SNAPSHOT['display_name']
        metadata['display_description'] = \
            DATA_IN_SNAPSHOT['display_description']
        params['metadata'] = metadata
        params['snapshot'] = DATA_IN_SNAPSHOT['id']

        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'PUT',
            '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME,
                            DATA_IN_VOLUME['id']),
            params,
            [httplib.OK, httplib.CREATED, httplib.ACCEPTED])

    def test_getvdev(self):
        self.dplcmd.get_vdev(DATA_IN_VOLUME['id'])
        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'GET',
            '/%s/%s/%s/' % (DPLCOMMON.DPL_VER_V1, DPLCOMMON.DPL_OBJ_VOLUME,
                            DATA_IN_VOLUME['id']),
            None,
            [httplib.OK, httplib.ACCEPTED, httplib.NOT_FOUND])

    def test_getvdevstatus(self):
        self.dplcmd.get_vdev_status(DATA_IN_VOLUME['id'], '123456')
        self.DPL_MOCK.send_cmd.assert_called_once_with(
            'GET',
            '/%s/%s/%s/?event_uuid=%s' % (DPLCOMMON.DPL_VER_V1,
                                          DPLCOMMON.DPL_OBJ_VOLUME,
                                          DATA_IN_VOLUME['id'],
                                          '123456'),
            None,