# Copyright 2015 CloudByte 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.

""" Test class for cloudbyte's cinder driver.

This involves mocking of elasticenter's json responses
when a method of this driver is unit tested.
"""

import json

import mock
import testtools
from testtools import matchers

from cinder import context
from cinder import exception
from cinder import test
from cinder.volume import configuration as conf
from cinder.volume.drivers.cloudbyte import cloudbyte
from cinder.volume import qos_specs
from cinder.volume import volume_types

# A fake list account response of cloudbyte's elasticenter
FAKE_LIST_ACCOUNT_RESPONSE = """{ "listAccountResponse" : {
    "count":1 ,
    "account" : [{
        "id": "d13a4e9e-0c05-4d2d-8a5e-5efd3ef058e0",
        "name": "CustomerA",
        "simpleid": 1,
        "description": "None",
        "iqnname": "iqn.2014-05.cvsacc1",
        "availIOPS": 508,
        "totaliops": 2000,
        "usedIOPS": 1492,
        "volumes": [],
        "storageBuckets": [],
        "tsms": [],
        "qosgroups": [],
        "filesystemslist": [],
        "currentUsedSpace": 53179,
        "currentAvailableSpace": 1249349,
        "currentThroughput": 156,
        "currentIOPS": 33,
        "currentLatency": 0,
        "currentThrottle": 0,
        "numericquota": 3145728.0,
        "currentnumericquota": 1253376.0,
        "currentavailablequota": 1892352.0,
        "revisionnumber": 1
    }]
    }}"""

# A fake list tsm response of cloudbyte's elasticenter
FAKE_LIST_TSM_RESPONSE = """{ "listTsmResponse" : {
    "count":1 ,
    "listTsm" : [{
        "id": "955eaf34-4221-3a77-82d0-99113b126fa8",
        "simpleid": 2,
        "name": "openstack",
        "ipaddress": "172.16.50.40",
        "accountname": "CustomerA",
        "sitename": "BLR",
        "clustername": "HAGrp1",
        "controllerName": "Controller",
        "controlleripaddress": "172.16.50.6",
        "clusterstatus": "Online",
        "hapoolstatus": "ONLINE",
        "hapoolname": "pool",
        "hapoolavailiops": 1700,
        "hapoolgrace": true,
        "hapoolavailtput": 6800,
        "poollatency": 10,
        "accountid": "d13a4e9e-0c05-4d2d-8a5e-5efd3ef058e0",
        "controllerid": "8c2f7084-99c0-36e6-9cb7-205e3ba4c813",
        "poolid": "adcbef8f-2193-3f2c-9bb1-fcaf977ae0fc",
        "datasetid": "87a23025-f2b2-39e9-85ac-9cda15bfed1a",
        "storageBuckets": [],
        "currentUsedSpace": 16384,
        "currentAvailableSpace": 188416,
        "currentTotalSpace": 204800,
        "currentThroughput": 12,
        "tpcontrol": "true",
        "currentIOPS": 0,
        "iopscontrol": "true",
        "gracecontrol": "false",
        "currentLatency": 0,
        "currentThrottle": 0,
        "iops": "1000",
        "availIOPS": "500",
        "availThroughput": "2000",
        "usedIOPS": "500",
        "usedThroughput": "2000",
        "throughput": "4000",
        "latency": "15",
        "graceallowed": true,
        "numericquota": 1048576.0,
        "currentnumericquota": 204800.0,
        "availablequota": 843776.0,
        "blocksize": "4",
        "type": "1",
        "iqnname": "iqn.2014-05.cvsacc1.openstack",
        "interfaceName": "em0",
        "revisionnumber": 0,
        "status": "Online",
        "subnet": "16",
        "managedstate": "Available",
        "configurationstate": "sync",
        "offlinenodes": "",
        "pooltakeover": "noTakeOver",
        "totalprovisionquota": "536576",
        "haNodeStatus": "Available",
        "ispooltakeoveronpartialfailure": true,
        "filesystemslist": [],
        "volumes": [],
        "qosgrouplist": []
    }]
    }}"""

# A fake add QOS group response of cloudbyte's elasticenter
FAKE_ADD_QOS_GROUP_RESPONSE = """{ "addqosgroupresponse" : {
    "qosgroup" : {
        "id": "d73662ac-6db8-3b2c-981a-012af4e2f7bd",
        "name": "QoS_DS1acc1openstacktsm",
        "tsmid": "8146146e-f67b-3942-8074-3074599207a4",
        "controllerid": "f1603e87-d1e6-3dcb-a549-7a6e77f82d86",
        "poolid": "73b567c0-e57d-37b5-b765-9d70725f59af",
        "parentid": "81ebdcbb-f73b-3337-8f32-222820e6acb9",
        "tsmName": "openstacktsm",
        "offlinenodes": "",
        "sitename": "site1",
        "clustername": "HA1",
        "controllerName": "node1",
        "clusterstatus": "Online",
        "currentThroughput": 0,
        "currentIOPS": 0,
        "currentLatency": 0,
        "currentThrottle": 0,
        "iopsvalue": "(0/100)",
        "throughputvalue": "(0/400)",
        "iops": "100",
        "iopscontrol": "true",
        "throughput": "400",
        "tpcontrol": "true",
        "blocksize": "4k",
        "latency": "15",
        "graceallowed": false,
        "type": "1",
        "revisionnumber": 0,
        "managedstate": "Available",
        "configurationstate": "init",
        "standardproviops": 0,
        "operatingblocksize": 0,
        "operatingcachehit": 0,
        "operatingiops": 0,
        "standardoperatingiops": 0
    }
    }}"""

# A fake create volume response of cloudbyte's elasticenter
FAKE_CREATE_VOLUME_RESPONSE = """{ "createvolumeresponse" : {
        "jobid": "f94e2257-9515-4a44-add0-4b16cb1bcf67"
    }}"""

# A fake query async job response of cloudbyte's elasticenter
FAKE_QUERY_ASYNC_JOB_RESULT_RESPONSE = """{ "queryasyncjobresultresponse" : {
    "accountid": "e8aca633-7bce-4ab7-915a-6d8847248467",
    "userid": "a83d1030-1b85-40f7-9479-f40e4dbdd5d5",
    "cmd": "com.cloudbyte.api.commands.CreateVolumeCmd",
    "msg": "5",
    "jobstatus": 1,
    "jobprocstatus": 0,
    "jobresultcode": 0,
    "jobresulttype": "object",
    "jobresult": {
    "storage": {
        "id": "92cfd601-bc1f-3fa7-8322-c492099f3326",
        "name": "DS1",
        "simpleid": 20,
        "compression": "off",
        "sync": "always",
        "noofcopies": 1,
        "recordsize": "4k",
        "deduplication": "off",
        "quota": "10G",
        "path": "devpool1/acc1openstacktsm/DS1",
        "tsmid": "8146146e-f67b-3942-8074-3074599207a4",
        "poolid": "73b567c0-e57d-37b5-b765-9d70725f59af",
        "mountpoint": "acc1DS1",
        "currentUsedSpace": 0,
        "currentAvailableSpace": 0,
        "currentTotalSpace": 0,
        "currentThroughput": 0,
        "currentIOPS": 0,
        "currentLatency": 0,
        "currentThrottle": 0,
        "tsmName": "openstacktsm",
        "hapoolname": "devpool1",
        "revisionnumber": 0,
        "blocklength": "512B",
        "nfsenabled": false,
        "cifsenabled": false,
        "iscsienabled": true,
        "fcenabled": false
    }
    },
    "created": "2014-06-16 15:49:49",
    "jobid": "f94e2257-9515-4a44-add0-4b16cb1bcf67"
    }}"""

# A fake list filesystem response of cloudbyte's elasticenter
FAKE_LIST_FILE_SYSTEM_RESPONSE = """{ "listFilesystemResponse" : {
    "count":1 ,
    "filesystem" : [{
        "id": "c93df32e-3a99-3491-8e10-cf318a7f9b7f",
        "name": "c93df32e3a9934918e10cf318a7f9b7f",
        "simpleid": 34,
        "type": "filesystem",
        "revisionnumber": 1,
        "path": "/cvsacc1DS1",
        "clusterid": "8b404f12-7975-4e4e-8549-7abeba397fc9",
        "clusterstatus": "Online",
        "Tsmid": "955eaf34-4221-3a77-82d0-99113b126fa8",
        "tsmType": "1",
        "accountid": "d13a4e9e-0c05-4d2d-8a5e-5efd3ef058e0",
        "poolid": "adcbef8f-2193-3f2c-9bb1-fcaf977ae0fc",
        "controllerid": "8c2f7084-99c0-36e6-9cb7-205e3ba4c813",
        "groupid": "663923c9-084b-3778-b13d-72f23d046b8d",
        "parentid": "08de7c14-62af-3992-8407-28f5f053e59b",
        "compression": "off",
        "sync": "always",
        "noofcopies": 1,
        "recordsize": "4k",
        "deduplication": "off",
        "quota": "1T",
        "unicode": "off",
        "casesensitivity": "sensitive",
        "readonly": false,
        "nfsenabled": true,
        "cifsenabled": false,
        "iscsienabled": false,
        "fcenabled": false,
        "currentUsedSpace": 19968,
        "currentAvailableSpace": 1028608,
        "currentTotalSpace": 1048576,
        "currentThroughput": 0,
        "currentIOPS": 0,
        "currentLatency": 0,
        "currentThrottle": 0,
        "numericquota": 1048576.0,
        "status": "Online",
        "managedstate": "Available",
        "configurationstate": "sync",
        "tsmName": "cvstsm1",
        "ipaddress": "172.16.50.35",
        "sitename": "BLR",
        "clustername": "HAGrp1",
        "controllerName": "Controller",
        "hapoolname": "pool",
        "hapoolgrace": true,
        "tsmgrace": true,
        "tsmcontrolgrace": "false",
        "accountname": "CustomerA",
        "groupname": "QoS_DS1cvsacc1cvstsm1",
        "iops": "500",
        "blocksize": "4",
        "throughput": "2000",
        "latency": "15",
        "graceallowed": false,
        "offlinenodes": "",
        "tpcontrol": "true",
        "iopscontrol": "true",
        "tsmAvailIops": "8",
        "tsmAvailTput": "32",
        "iqnname": "",
        "mountpoint": "cvsacc1DS1",
        "pooltakeover": "noTakeOver",
        "volumeaccessible": "true",
        "localschedulecount": 0
    }]
    }}"""

# A fake list storage snapshot response of cloudbyte's elasticenter
FAKE_LIST_STORAGE_SNAPSHOTS_RESPONSE = """{ "listDatasetSnapshotsResponse" : {
    "count":1 ,
    "snapshot" : [{
        "name": "snap_c60890b1f23646f29e6d51e6e592cee6",
        "path": "DS1@snap_c60890b1f23646f29e6d51e6e592cee6",
        "availMem": "-",
        "usedMem": "0",
        "refer": "26K",
        "mountpoint": "-",
        "timestamp": "Mon Jun 16 2014 14:41",
        "clones": 0,
        "pooltakeover": "noTakeOver",
        "managedstate": "Available"
    }]
    }}"""

# A fake delete storage snapshot response of cloudbyte's elasticenter
FAKE_DELETE_STORAGE_SNAPSHOT_RESPONSE = """{ "deleteSnapshotResponse" :  {
    "DeleteSnapshot" : {
        "status": "success"
    }
    }}"""

# A fake update volume iscsi service response of cloudbyte's elasticenter
FAKE_UPDATE_VOLUME_ISCSI_SERVICE_RESPONSE = (
    """{ "updatingvolumeiscsidetails" :  {
    "viscsioptions" : {
        "id": "0426c04a-8fac-30e8-a8ad-ddab2f08013a",
        "volume_id": "12371e7c-392b-34b9-ac43-073b3c85f1d1",
        "ag_id": "4459248d-e9f1-3d2a-b7e8-b5d9ce587fc1",
        "ig_id": "527bd65b-ebec-39ce-a5e9-9dd1106cc0fc",
        "iqnname": "iqn.2014-06.acc1.openstacktsm:acc1DS1",
        "authmethod": "None",
        "status": true,
        "usn": "12371e7c392b34b9ac43073b3c85f1d1",
        "initialdigest": "Auto",
        "queuedepth": "32",
        "inqproduct": 0,
        "inqrevision": 0,
        "blocklength": "512B"
    }}
    }""")

# A fake list iscsi initiator response of cloudbyte's elasticenter
FAKE_LIST_ISCSI_INITIATOR_RESPONSE = """{ "listInitiatorsResponse" : {
    "count":2 ,
    "initiator" : [{
        "id": "527bd65b-ebec-39ce-a5e9-9dd1106cc0fc",
        "accountid": "86c5251a-9044-4690-b924-0d97627aeb8c",
        "name": "ALL",
        "netmask": "ALL",
        "initiatorgroup": "ALL"
        },{
        "id": "203e0235-1d5a-3130-9204-98e3f642a564",
        "accountid": "86c5251a-9044-4690-b924-0d97627aeb8c",
        "name": "None",
        "netmask": "None",
        "initiatorgroup": "None"
        }]
     }}"""

# A fake delete file system response of cloudbyte's elasticenter
FAKE_DELETE_FILE_SYSTEM_RESPONSE = """{ "deleteFileSystemResponse" : {
        "jobid": "e1fe861a-17e3-41b5-ae7c-937caac62cdf"
    }}"""

# A fake create storage snapshot response of cloudbyte's elasticenter
FAKE_CREATE_STORAGE_SNAPSHOT_RESPONSE = (
    """{ "createStorageSnapshotResponse" :  {
    "StorageSnapshot" : {
        "id": "21d7a92a-f15e-3f5b-b981-cb30697b8028",
        "name": "snap_c60890b1f23646f29e6d51e6e592cee6",
        "usn": "21d7a92af15e3f5bb981cb30697b8028",
        "lunusn": "12371e7c392b34b9ac43073b3c85f1d1",
        "lunid": "12371e7c-392b-34b9-ac43-073b3c85f1d1",
        "scsiEnabled": false
    }}
    }""")

# A fake list volume iscsi service response of cloudbyte's elasticenter
FAKE_LIST_VOLUME_ISCSI_SERVICE_RESPONSE = (
    """{ "listVolumeiSCSIServiceResponse" : {
    "count":1 ,
    "iSCSIService" : [{
        "id": "67ddcbf4-6887-3ced-8695-7b9cdffce885",
        "volume_id": "c93df32e-3a99-3491-8e10-cf318a7f9b7f",
        "ag_id": "4459248d-e9f1-3d2a-b7e8-b5d9ce587fc1",
        "ig_id": "203e0235-1d5a-3130-9204-98e3f642a564",
        "iqnname": "iqn.2014-06.acc1.openstacktsm:acc1DS1",
        "authmethod": "None",
        "status": true,
        "usn": "92cfd601bc1f3fa78322c492099f3326",
        "initialdigest": "Auto",
        "queuedepth": "32",
        "inqproduct": 0,
        "inqrevision": 0,
        "blocklength": "512B"
    }]
    }}""")

# A fake clone dataset snapshot response of cloudbyte's elasticenter
FAKE_CLONE_DATASET_SNAPSHOT_RESPONSE = """{ "cloneDatasetSnapshot" : {
    "filesystem" : {
        "id": "dcd46a57-e3f4-3fc1-8dd8-2e658d9ebb11",
        "name": "DS1Snap1clone1",
        "simpleid": 21,
        "type": "volume",
        "revisionnumber": 1,
        "path": "iqn.2014-06.acc1.openstacktsm:acc1DS1Snap1clone1",
        "clusterid": "0ff44329-9a69-4611-bac2-6eaf1b08bb18",
        "clusterstatus": "Online",
        "Tsmid": "8146146e-f67b-3942-8074-3074599207a4",
        "tsmType": "1",
        "accountid": "86c5251a-9044-4690-b924-0d97627aeb8c",
        "poolid": "73b567c0-e57d-37b5-b765-9d70725f59af",
        "controllerid": "f1603e87-d1e6-3dcb-a549-7a6e77f82d86",
        "groupid": "d73662ac-6db8-3b2c-981a-012af4e2f7bd",
        "parentid": "81ebdcbb-f73b-3337-8f32-222820e6acb9",
        "compression": "off",
        "sync": "always",
        "noofcopies": 1,
        "recordsize": "4k",
        "deduplication": "off",
        "quota": "10G",
        "unicode": "off",
        "casesensitivity": "sensitive",
        "readonly": false,
        "nfsenabled": false,
        "cifsenabled": false,
        "iscsienabled": true,
        "fcenabled": false,
        "currentUsedSpace": 0,
        "currentAvailableSpace": 10240,
        "currentTotalSpace": 10240,
        "currentThroughput": 0,
        "currentIOPS": 0,
        "currentLatency": 0,
        "currentThrottle": 0,
        "numericquota": 10240.0,
        "status": "Online",
        "managedstate": "Available",
        "configurationstate": "sync",
        "tsmName": "openstacktsm",
        "ipaddress": "20.10.22.56",
        "sitename": "site1",
        "clustername": "HA1",
        "controllerName": "node1",
        "hapoolname": "devpool1",
        "hapoolgrace": true,
        "tsmgrace": true,
        "tsmcontrolgrace": "false",
        "accountname": "acc1",
        "groupname": "QoS_DS1acc1openstacktsm",
        "iops": "100",
        "blocksize": "4k",
        "throughput": "400",
        "latency": "15",
        "graceallowed": false,
        "offlinenodes": "",
        "tpcontrol": "true",
        "iopscontrol": "true",
        "tsmAvailIops": "700",
        "tsmAvailTput": "2800",
        "iqnname": "iqn.2014-06.acc1.openstacktsm:acc1DS1Snap1clone1",
        "mountpoint": "acc1DS1Snap1clone1",
        "blocklength": "512B",
        "volumeaccessible": "true",
        "localschedulecount": 0
    }
    }}"""

# A fake update filesystem response of cloudbyte's elasticenter
FAKE_UPDATE_FILE_SYSTEM_RESPONSE = """{ "updatefilesystemresponse" : {
    "count":1 ,
    "filesystem" : [{
        "id": "92cfd601-bc1f-3fa7-8322-c492099f3326",
        "name": "DS1",
        "simpleid": 20,
        "type": "volume",
        "revisionnumber": 1,
        "path": "iqn.2014-06.acc1.openstacktsm:acc1DS1",
        "clusterid": "0ff44329-9a69-4611-bac2-6eaf1b08bb18",
        "clusterstatus": "Online",
        "Tsmid": "8146146e-f67b-3942-8074-3074599207a4",
        "tsmType": "1",
        "accountid": "86c5251a-9044-4690-b924-0d97627aeb8c",
        "poolid": "73b567c0-e57d-37b5-b765-9d70725f59af",
        "controllerid": "f1603e87-d1e6-3dcb-a549-7a6e77f82d86",
        "groupid": "d73662ac-6db8-3b2c-981a-012af4e2f7bd",
        "parentid": "81ebdcbb-f73b-3337-8f32-222820e6acb9",
        "compression": "off",
        "sync": "always",
        "noofcopies": 1,
        "recordsize": "4k",
        "deduplication": "off",
        "quota": "12G",
        "unicode": "off",
        "casesensitivity": "sensitive",
        "readonly": false,
        "nfsenabled": false,
        "cifsenabled": false,
        "iscsienabled": true,
        "fcenabled": false,
        "currentUsedSpace": 0,
        "currentAvailableSpace": 10240,
        "currentTotalSpace": 10240,
        "currentThroughput": 0,
        "currentIOPS": 0,
        "currentLatency": 0,
        "currentThrottle": 0,
        "numericquota": 12288.0,
        "status": "Online",
        "managedstate": "Available",
        "configurationstate": "sync",
        "tsmName": "openstacktsm",
        "ipaddress": "20.10.22.56",
        "sitename": "site1",
        "clustername": "HA1",
        "controllerName": "node1",
        "hapoolname": "devpool1",
        "hapoolgrace": true,
        "tsmgrace": true,
        "tsmcontrolgrace": "false",
        "accountname": "acc1",
        "groupname": "QoS_DS1acc1openstacktsm",
        "iops": "100",
        "blocksize": "4k",
        "throughput": "400",
        "latency": "15",
        "graceallowed": false,
        "offlinenodes": "",
        "tpcontrol": "true",
        "iopscontrol": "true",
        "tsmAvailIops": "700",
        "tsmAvailTput": "2800",
        "iqnname": "iqn.2014-06.acc1.openstacktsm:acc1DS1",
        "mountpoint": "acc1DS1",
        "blocklength": "512B",
        "volumeaccessible": "true",
        "localschedulecount": 0
    }]
    }}"""

# A fake update QOS group response of cloudbyte's elasticenter
FAKE_UPDATE_QOS_GROUP_RESPONSE = """{ "updateqosresponse" : {
    "count":1 ,
    "qosgroup" : [{
        "id": "d73662ac-6db8-3b2c-981a-012af4e2f7bd",
        "name": "QoS_DS1acc1openstacktsm",
        "tsmid": "8146146e-f67b-3942-8074-3074599207a4",
        "controllerid": "f1603e87-d1e6-3dcb-a549-7a6e77f82d86",
        "poolid": "73b567c0-e57d-37b5-b765-9d70725f59af",
        "parentid": "81ebdcbb-f73b-3337-8f32-222820e6acb9",
        "tsmName": "openstacktsm",
        "offlinenodes": "",
        "sitename": "site1",
        "clustername": "HA1",
        "controllerName": "node1",
        "clusterstatus": "Online",
        "currentThroughput": 0,
        "currentIOPS": 0,
        "currentLatency": 0,
        "currentThrottle": 0,
        "iopsvalue": "(0/101)",
        "throughputvalue": "(0/404)",
        "iops": "101",
        "iopscontrol": "true",
        "throughput": "404",
        "tpcontrol": "true",
        "blocksize": "4k",
        "latency": "15",
        "graceallowed": true,
        "type": "1",
        "revisionnumber": 2,
        "managedstate": "Available",
        "configurationstate": "sync",
        "status": "Online",
        "standardproviops": 0,
        "operatingblocksize": 0,
        "operatingcachehit": 0,
        "operatingiops": 0,
        "standardoperatingiops": 0
    }]
    }}"""

# A fake list iSCSI auth user response of cloudbyte's elasticenter
FAKE_LIST_ISCSI_AUTH_USER_RESPONSE = """{ "listiSCSIAuthUsersResponse" : {
    "count":1 ,
    "authuser" : [{
        "id": "53d00164-a974-31b8-a854-bd346a8ea937",
        "accountid": "12d41531-c41a-4ab7-abe2-ce0db2570119",
        "authgroupid": "537744eb-c594-3145-85c0-96079922b894",
        "chapusername": "fakeauthgroupchapuser",
        "chappassword": "fakeauthgroupchapsecret",
        "mutualchapusername": "fakeauthgroupmutualchapuser",
        "mutualchappassword": "fakeauthgroupmutualchapsecret"
    }]
    }}"""

# A fake list iSCSI auth group response of cloudbyte's elasticenter
FAKE_LIST_ISCSI_AUTH_GROUP_RESPONSE = """{ "listiSCSIAuthGroupResponse" : {
    "count":2 ,
    "authgroup" : [{
        "id": "32d935ee-a60f-3681-b792-d8ccfe7e8e7f",
        "name": "None",
        "comment": "None"
        }, {
        "id": "537744eb-c594-3145-85c0-96079922b894",
        "name": "fakeauthgroup",
        "comment": "Fake Auth Group For Openstack "
    }]
    }}"""


# This dict maps the http commands of elasticenter
# with its respective fake responses
MAP_COMMAND_TO_FAKE_RESPONSE = {}

MAP_COMMAND_TO_FAKE_RESPONSE['deleteFileSystem'] = (
    json.loads(FAKE_DELETE_FILE_SYSTEM_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["listFileSystem"] = (
    json.loads(FAKE_LIST_FILE_SYSTEM_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["deleteSnapshot"] = (
    json.loads(FAKE_DELETE_STORAGE_SNAPSHOT_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["updateVolumeiSCSIService"] = (
    json.loads(FAKE_UPDATE_VOLUME_ISCSI_SERVICE_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["createStorageSnapshot"] = (
    json.loads(FAKE_CREATE_STORAGE_SNAPSHOT_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["listAccount"] = (
    json.loads(FAKE_LIST_ACCOUNT_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["listTsm"] = (
    json.loads(FAKE_LIST_TSM_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["addQosGroup"] = (
    json.loads(FAKE_ADD_QOS_GROUP_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["queryAsyncJobResult"] = (
    json.loads(FAKE_QUERY_ASYNC_JOB_RESULT_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["createVolume"] = (
    json.loads(FAKE_CREATE_VOLUME_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["listVolumeiSCSIService"] = (
    json.loads(FAKE_LIST_VOLUME_ISCSI_SERVICE_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE["listiSCSIInitiator"] = (
    json.loads(FAKE_LIST_ISCSI_INITIATOR_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE['cloneDatasetSnapshot'] = (
    json.loads(FAKE_CLONE_DATASET_SNAPSHOT_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE['updateFileSystem'] = (
    json.loads(FAKE_UPDATE_FILE_SYSTEM_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE['updateQosGroup'] = (
    json.loads(FAKE_UPDATE_QOS_GROUP_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE['listStorageSnapshots'] = (
    json.loads(FAKE_LIST_STORAGE_SNAPSHOTS_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE['listiSCSIAuthUser'] = (
    json.loads(FAKE_LIST_ISCSI_AUTH_USER_RESPONSE))
MAP_COMMAND_TO_FAKE_RESPONSE['listiSCSIAuthGroup'] = (
    json.loads(FAKE_LIST_ISCSI_AUTH_GROUP_RESPONSE))


class CloudByteISCSIDriverTestCase(test.TestCase):

    def setUp(self):
        super(CloudByteISCSIDriverTestCase, self).setUp()
        self._configure_driver()
        self.ctxt = context.get_admin_context()

    def _configure_driver(self):

        configuration = conf.Configuration(None, None)

        # initialize the elasticenter iscsi driver
        self.driver = cloudbyte.CloudByteISCSIDriver(
            configuration=configuration)

        # override some parts of driver configuration
        self.driver.configuration.cb_tsm_name = 'openstack'
        self.driver.configuration.cb_account_name = 'CustomerA'
        self.driver.configuration.cb_auth_group = 'fakeauthgroup'
        self.driver.configuration.cb_apikey = 'G4ZUB39WH7lbiZhPhL3nbd'
        self.driver.configuration.san_ip = '172.16.51.30'

    def _side_effect_api_req(self, cmd, params, version='1.0'):
        """This is a side effect function.

        The return value is determined based on cmd argument.
        The signature matches exactly with the method it tries
        to mock.
        """
        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_api_req_to_create_vol(self, cmd, params, version='1.0'):
        """This is a side effect function."""
        if cmd == 'createVolume':
            return {}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_api_req_to_delete_file_system(
            self, cmd, params, version='1.0'):
        """This is a side effect function."""
        if cmd == 'deleteFileSystem':
            return {}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_api_req_to_query_asyncjob_response(
            self, cmd, params, version='1.0'):
        """This is a side effect function."""
        if cmd == 'queryAsyncJobResult':
            return {}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_api_req_to_query_asyncjob(
            self, cmd, params, version='1.0'):
        """This is a side effect function."""

        if cmd == 'queryAsyncJobResult':
            return {'queryasyncjobresultresponse': {'jobstatus': 0}}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_api_req_to_list_tsm(self, cmd, params, version='1.0'):
        """This is a side effect function."""
        if cmd == 'listTsm':
            return {}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _none_response_to_list_tsm(self, cmd, params, version='1.0'):
        """This is a side effect function."""
        if cmd == 'listTsm':
            return {"listTsmResponse": {}}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_api_req_to_list_iscsi_auth_group(self, cmd, params,
                                                      version='1.0'):
        """This is a side effect function."""
        if cmd == 'listiSCSIAuthGroup':
            return {}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_api_req_to_list_iscsi_auth_user(self, cmd, params,
                                                     version='1.0'):
        """This is a side effect function."""
        if cmd == 'listiSCSIAuthUser':
            return {}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_enable_chap(self):
        """This is a side effect function."""
        self.driver.cb_use_chap = True

    def _side_effect_disable_chap(self):
        """This is a side effect function."""
        self.driver.cb_use_chap = False

    def _side_effect_api_req_to_list_filesystem(
            self, cmd, params, version='1.0'):
        """This is a side effect function."""
        if cmd == 'listFileSystem':
            return {}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _fake_api_req_to_list_filesystem(
            self, cmd, params, version='1.0'):
        """This is a side effect function."""
        if cmd == 'listFileSystem':
            return {"listFilesystemResponse": {"filesystem": [{}]}}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_api_req_to_list_vol_iscsi_service(
            self, cmd, params, version='1.0'):
        """This is a side effect function."""
        if cmd == 'listVolumeiSCSIService':
            return {}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_api_req_to_list_iscsi_initiator(
            self, cmd, params, version='1.0'):
        """This is a side effect function."""
        if cmd == 'listiSCSIInitiator':
            return {}

        return MAP_COMMAND_TO_FAKE_RESPONSE[cmd]

    def _side_effect_create_vol_from_snap(self, cloned_volume, snapshot):
        """This is a side effect function."""
        return {}

    def _side_effect_create_snapshot(self, snapshot):
        """This is a side effect function."""
        model_update = {}
        model_update['provider_id'] = "devpool1/acc1openstacktsm/DS1@DS1Snap1"
        return model_update

    def _side_effect_get_connection(self, host, url):
        """This is a side effect function."""

        return_obj = {}

        return_obj['http_status'] = 200

        # mock the response data
        return_obj['data'] = MAP_COMMAND_TO_FAKE_RESPONSE['listTsm']
        return_obj['error'] = None

        return return_obj

    def _side_effect_get_err_connection(self, host, url):
        """This is a side effect function."""

        return_obj = {}

        return_obj['http_status'] = 500

        # mock the response data
        return_obj['data'] = None
        return_obj['error'] = "Http status: 500, Error: Elasticenter "
        "is not available."

        return return_obj

    def _side_effect_get_err_connection2(self, host, url):
        """This is a side effect function."""

        msg = ("Error executing CloudByte API %(cmd)s , Error: %(err)s" %
               {'cmd': 'MockTest', 'err': 'Error'})
        raise exception.VolumeBackendAPIException(msg)

    def _get_fake_volume_id(self):

        # Get the filesystems
        fs_list = MAP_COMMAND_TO_FAKE_RESPONSE['listFileSystem']
        filesystems = fs_list['listFilesystemResponse']['filesystem']

        # Get the volume id from the first filesystem
        volume_id = filesystems[0]['id']

        return volume_id

    def _fake_get_volume_type(self, ctxt, type_id):
        fake_type = {'qos_specs_id': 'fake-id',
                     'extra_specs': {'qos:iops': '100000'},
                     'id': 'fake-volume-type-id'}

        return fake_type

    def _fake_get_qos_spec(self, ctxt, spec_id):
        fake_qos_spec = {'id': 'fake-qos-spec-id',
                         'specs': {'iops': '1000',
                                   'graceallowed': 'true',
                                   'readonly': 'true'}}
        return fake_qos_spec

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_execute_and_get_response_details')
    def test_api_request_for_cloudbyte(self, mock_conn):

        # Test - I

        # configure the mocks with respective side-effects
        mock_conn.side_effect = self._side_effect_get_connection

        # run the test
        data = self.driver._api_request_for_cloudbyte('listTsm', {})

        # assert the data attributes
        self.assertEqual(1, data['listTsmResponse']['count'])

        # Test - II

        # configure the mocks with side-effects
        mock_conn.reset_mock()
        mock_conn.side_effect = self._side_effect_get_err_connection

        # run the test
        with testtools.ExpectedException(
                exception.VolumeBackendAPIException,
                'Bad or unexpected response from the storage volume '
                'backend API: Failed to execute CloudByte API'):
            self.driver._api_request_for_cloudbyte('listTsm', {})

        # Test - III

        # configure the mocks with side-effects
        mock_conn.reset_mock()
        mock_conn.side_effect = self._side_effect_get_err_connection2

        # run the test
        with testtools.ExpectedException(
                exception.VolumeBackendAPIException,
                'Error executing CloudByte API'):
            self.driver._api_request_for_cloudbyte('listTsm', {})

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    def test_delete_volume(self, mock_api_req):

        # prepare the dependencies
        fake_volume_id = self._get_fake_volume_id()
        volume = {'id': fake_volume_id, 'provider_id': fake_volume_id}

        # Test-I

        mock_api_req.side_effect = self._side_effect_api_req

        # run the test
        self.driver.delete_volume(volume)

        # assert that 7 api calls were invoked
        self.assertEqual(7, mock_api_req.call_count)

        # Test-II

        # reset & re-configure mock
        volume['provider_id'] = None
        mock_api_req.reset_mock()
        mock_api_req.side_effect = self._side_effect_api_req

        # run the test
        self.driver.delete_volume(volume)

        # assert that no api calls were invoked
        self.assertEqual(0, mock_api_req.call_count)

        # Test-III

        # re-configure the dependencies
        volume['provider_id'] = fake_volume_id

        # reset & re-configure mock
        mock_api_req.reset_mock()

        # configure or re-configure the mocks
        mock_api_req.side_effect = (
            self._side_effect_api_req_to_delete_file_system)

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.delete_volume,
                          volume)

        # assert that 6 api calls were invoked
        self.assertEqual(6, mock_api_req.call_count)

        # Test - IV

        # reset the mocks
        mock_api_req.reset_mock()

        # configure or re-configure the mocks
        mock_api_req.side_effect = (
            self._side_effect_api_req_to_query_asyncjob_response)

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.delete_volume,
                          volume)

        # assert that 7 api calls were invoked
        self.assertEqual(7, mock_api_req.call_count)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    def test_delete_snapshot(self, mock_api_req):

        snapshot = {
            'id': 'SomeID',
            'provider_id': 'devpool1/acc1openstacktsm/DS1@DS1Snap1',
            'display_name': 'DS1Snap1',
            'volume_id': 'SomeVol',
            'volume': {
                'display_name': 'DS1'
            }

        }

        # Test - I

        # now run the test
        self.driver.delete_snapshot(snapshot)

        # assert that 1 api call was invoked
        self.assertEqual(1, mock_api_req.call_count)

        # Test - II

        # reconfigure the dependencies
        snapshot['provider_id'] = None

        # reset & reconfigure the mock
        mock_api_req.reset_mock()
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        self.driver.delete_snapshot(snapshot)

        # assert that no api calls were invoked
        self.assertEqual(0, mock_api_req.call_count)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    def test_create_snapshot(self, mock_api_req):

        # prepare the dependencies
        fake_volume_id = self._get_fake_volume_id()

        snapshot = {
            'id': 'c60890b1-f236-46f2-9e6d-51e6e592cee6',
            'display_name': 'DS1Snap1',
            'volume_id': 'SomeVol',
            'volume': {
                'display_name': 'DS1',
                'provider_id': fake_volume_id

            }
        }

        # Test - I

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        model_update = self.driver.create_snapshot(snapshot)

        # assert that 2 api calls were invoked
        self.assertEqual(2, mock_api_req.call_count)

        self.assertEqual('DS1@snap_c60890b1f23646f29e6d51e6e592cee6',
                         model_update['provider_id'])

        # Test - II

        # reconfigure the dependencies
        snapshot['volume']['provider_id'] = None

        # reset & reconfigure the mock
        mock_api_req.reset_mock()
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test & assert the exception
        with testtools.ExpectedException(
                exception.VolumeBackendAPIException,
                'Bad or unexpected response from the storage volume '
                'backend API: Failed to create snapshot'):
            self.driver.create_snapshot(snapshot)

        # assert that no api calls were invoked
        self.assertEqual(0, mock_api_req.call_count)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    def test_create_volume(self, mock_api_req):

        # prepare the dependencies
        fake_volume_id = self._get_fake_volume_id()

        volume = {
            'id': fake_volume_id,
            'size': 22,
            'volume_type_id': None
        }

        # Test - I

        # enable CHAP
        self._side_effect_enable_chap()

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        provider_details = self.driver.create_volume(volume)

        # assert equality checks for certain configuration attributes
        self.assertEqual(
            'openstack', self.driver.configuration.cb_tsm_name)
        self.assertEqual(
            'CustomerA', self.driver.configuration.cb_account_name)
        self.assertEqual(
            'fakeauthgroup', self.driver.configuration.cb_auth_group)

        # assert the result
        self.assertEqual(
            'CHAP fakeauthgroupchapuser fakeauthgroupchapsecret',
            provider_details['provider_auth'])
        self.assertThat(
            provider_details['provider_location'],
            matchers.Contains('172.16.50.35:3260'))

        # assert the invoked api calls to CloudByte Storage
        self.assertEqual(11, mock_api_req.call_count)

        # Test - II

        # reset the mock
        mock_api_req.reset_mock()

        # disable CHAP
        self._side_effect_disable_chap()

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        provider_details = self.driver.create_volume(volume)

        # assert equality checks for certain configuration attributes
        self.assertEqual(
            'openstack', self.driver.configuration.cb_tsm_name)
        self.assertEqual(
            'CustomerA', self.driver.configuration.cb_account_name)

        # assert the result
        self.assertIsNone(provider_details['provider_auth'])
        self.assertThat(
            provider_details['provider_location'],
            matchers.Contains('172.16.50.35:3260'))

        # assert the invoked api calls to CloudByte Storage
        self.assertEqual(9, mock_api_req.call_count)

        # Test - III

        # reconfigure the dependencies
        volume['id'] = 'NotExists'
        del volume['size']

        # reset & reconfigure the mock
        mock_api_req.reset_mock()
        mock_api_req.side_effect = self._side_effect_api_req

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume,
                          volume)

        # Test - IV

        # reconfigure the dependencies
        volume['id'] = 'abc'

        # reset the mocks
        mock_api_req.reset_mock()

        # configure or re-configure the mocks
        mock_api_req.side_effect = self._side_effect_api_req_to_create_vol

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume,
                          volume)

        # Test - V

        # reconfigure the dependencies
        # reset the mocks
        mock_api_req.reset_mock()

        # configure or re-configure the mocks
        mock_api_req.side_effect = self._side_effect_api_req_to_list_filesystem

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume,
                          volume)

        # Test - VI

        volume['id'] = fake_volume_id
        # reconfigure the dependencies
        # reset the mocks
        mock_api_req.reset_mock()

        # configure or re-configure the mocks
        mock_api_req.side_effect = (
            self._side_effect_api_req_to_list_vol_iscsi_service)

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume,
                          volume)

        # Test - VII

        # reconfigure the dependencies
        # reset the mocks
        mock_api_req.reset_mock()

        # configure or re-configure the mocks
        mock_api_req.side_effect = (
            self._side_effect_api_req_to_list_iscsi_initiator)

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume,
                          volume)

        # Test - VIII

        volume['id'] = fake_volume_id
        volume['size'] = 22

        # reconfigure the dependencies
        # reset the mocks
        mock_api_req.reset_mock()

        # configure or re-configure the mocks
        mock_api_req.side_effect = (
            self._none_response_to_list_tsm)

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume,
                          volume)

        # Test - IX

        volume['id'] = fake_volume_id
        volume['size'] = 22

        # reconfigure the dependencies
        # reset the mocks
        mock_api_req.reset_mock()

        # configure or re-configure the mocks
        mock_api_req.side_effect = (
            self._side_effect_api_req_to_create_vol)

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume,
                          volume)

        # Test - X

        # reset the mocks
        mock_api_req.reset_mock()

        # configure or re-configure the mocks
        mock_api_req.side_effect = (
            self._side_effect_api_req_to_query_asyncjob_response)

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume,
                          volume)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       'create_volume_from_snapshot')
    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       'create_snapshot')
    def test_create_cloned_volume(self, mock_create_snapshot,
                                  mock_create_vol_from_snap, mock_api_req):

        # prepare the input test data
        fake_volume_id = self._get_fake_volume_id()

        src_volume = {'display_name': 'DS1Snap1'}

        cloned_volume = {
            'source_volid': fake_volume_id,
            'id': 'SomeNewID',
            'display_name': 'CloneOfDS1Snap1'
        }

        # Test - I

        # configure the mocks with respective sideeffects
        mock_api_req.side_effect = self._side_effect_api_req
        mock_create_vol_from_snap.side_effect = (
            self._side_effect_create_vol_from_snap)
        mock_create_snapshot.side_effect = (
            self._side_effect_create_snapshot)

        # now run the test
        self.driver.create_cloned_volume(cloned_volume, src_volume)

        # assert that n api calls were invoked
        self.assertEqual(0, mock_api_req.call_count)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    def test_create_volume_from_snapshot(self, mock_api_req):

        # prepare the input test data
        fake_volume_id = self._get_fake_volume_id()

        snapshot = {
            'volume_id': fake_volume_id,
            'provider_id': 'devpool1/acc1openstacktsm/DS1@DS1Snap1',
            'id': 'SomeSnapID',
            'volume': {
                'provider_id': fake_volume_id
            }
        }

        cloned_volume = {
            'display_name': 'CloneOfDS1Snap1',
            'id': 'ClonedVolID'
        }

        # Test - I

        # enable CHAP
        self._side_effect_enable_chap()

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        provider_details = (
            self.driver.create_volume_from_snapshot(cloned_volume, snapshot))

        # assert the result
        self.assertEqual(
            'CHAP fakeauthgroupchapuser fakeauthgroupchapsecret',
            provider_details['provider_auth'])
        self.assertEqual(
            '20.10.22.56:3260 '
            'iqn.2014-06.acc1.openstacktsm:acc1DS1Snap1clone1 0',
            provider_details['provider_location'])

        # assert the invoked api calls to CloudByte Storage
        self.assertEqual(4, mock_api_req.call_count)

        # Test - II

        # reset the mocks
        mock_api_req.reset_mock()

        # disable CHAP
        self._side_effect_disable_chap()

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        provider_details = (
            self.driver.create_volume_from_snapshot(cloned_volume, snapshot))

        # assert the result
        self.assertIsNone(provider_details['provider_auth'])
        self.assertEqual(
            '20.10.22.56:3260 '
            'iqn.2014-06.acc1.openstacktsm:acc1DS1Snap1clone1 0',
            provider_details['provider_location'])

        # assert n api calls were invoked
        self.assertEqual(1, mock_api_req.call_count)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    def test_extend_volume(self, mock_api_req):

        # prepare the input test data
        fake_volume_id = self._get_fake_volume_id()

        volume = {
            'id': 'SomeID',
            'provider_id': fake_volume_id
        }

        new_size = '2'

        # Test - I

        # configure the mock with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        self.driver.extend_volume(volume, new_size)

        # assert n api calls were invoked
        self.assertEqual(1, mock_api_req.call_count)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    def test_create_export(self, mock_api_req):

        # Test - I

        # enable CHAP
        self._side_effect_enable_chap()

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        model_update = self.driver.create_export({}, {}, {})

        # assert the result
        self.assertEqual('CHAP fakeauthgroupchapuser fakeauthgroupchapsecret',
                         model_update['provider_auth'])

        # Test - II

        # reset the mocks
        mock_api_req.reset_mock()

        # disable CHAP
        self._side_effect_disable_chap()

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        model_update = self.driver.create_export({}, {}, {})

        # assert the result
        self.assertIsNone(model_update['provider_auth'])

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    def test_ensure_export(self, mock_api_req):

        # Test - I

        # enable CHAP
        self._side_effect_enable_chap()

        # configure the mock with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        model_update = self.driver.ensure_export({}, {})

        # assert the result to have a provider_auth attribute
        self.assertEqual('CHAP fakeauthgroupchapuser fakeauthgroupchapsecret',
                         model_update['provider_auth'])

        # Test - II

        # reset the mocks
        mock_api_req.reset_mock()

        # disable CHAP
        self._side_effect_disable_chap()

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req

        # now run the test
        model_update = self.driver.create_export({}, {}, {})

        # assert the result
        self.assertIsNone(model_update['provider_auth'])

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    def test_get_volume_stats(self, mock_api_req):

        # configure the mock with a side-effect
        mock_api_req.side_effect = self._side_effect_api_req

        # Test - I

        # run the test
        vol_stats = self.driver.get_volume_stats()

        # assert 0 api calls were invoked
        self.assertEqual(0, mock_api_req.call_count)

        # Test - II

        # run the test with refresh as True
        vol_stats = self.driver.get_volume_stats(refresh=True)

        # assert n api calls were invoked
        self.assertEqual(1, mock_api_req.call_count)

        # assert the result attributes with respective values
        self.assertEqual(1024.0, vol_stats['total_capacity_gb'])
        self.assertEqual(824.0, vol_stats['free_capacity_gb'])
        self.assertEqual(0, vol_stats['reserved_percentage'])
        self.assertEqual('CloudByte', vol_stats['vendor_name'])
        self.assertEqual('iSCSI', vol_stats['storage_protocol'])

        # Test - III

        # configure the mocks with side-effect
        mock_api_req.reset_mock()
        mock_api_req.side_effect = self._side_effect_api_req_to_list_tsm

        # run the test with refresh as True
        with testtools.ExpectedException(
                exception.VolumeBackendAPIException,
                "Bad or unexpected response from the storage volume "
                "backend API: No response was received from CloudByte "
                "storage list tsm API call."):
            self.driver.get_volume_stats(refresh=True)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    @mock.patch.object(volume_types,
                       'get_volume_type')
    @mock.patch.object(qos_specs,
                       'get_qos_specs')
    def test_retype(self, get_qos_spec, get_volume_type, mock_api_req):

        # prepare the input test data
        fake_new_type = {'id': 'fake-new-type-id'}
        fake_volume_id = self._get_fake_volume_id()

        volume = {
            'id': 'SomeID',
            'provider_id': fake_volume_id
        }

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req
        get_qos_spec.side_effect = self._fake_get_qos_spec
        get_volume_type.side_effect = self._fake_get_volume_type

        self.assertTrue(self.driver.retype(self.ctxt,
                                           volume,
                                           fake_new_type, None, None))

        # assert the invoked api calls
        self.assertEqual(3, mock_api_req.call_count)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    @mock.patch.object(volume_types,
                       'get_volume_type')
    @mock.patch.object(qos_specs,
                       'get_qos_specs')
    def test_retype_without_provider_id(self, get_qos_spec, get_volume_type,
                                        mock_api_req):

        # prepare the input test data
        fake_new_type = {'id': 'fake-new-type-id'}
        volume = {'id': 'SomeID'}

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req
        get_qos_spec.side_effect = self._fake_get_qos_spec
        get_volume_type.side_effect = self._fake_get_volume_type

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.retype,
                          self.ctxt, volume, fake_new_type, None, None)

    @mock.patch.object(cloudbyte.CloudByteISCSIDriver,
                       '_api_request_for_cloudbyte')
    @mock.patch.object(volume_types,
                       'get_volume_type')
    @mock.patch.object(qos_specs,
                       'get_qos_specs')
    def test_retype_without_filesystem(self, get_qos_spec, get_volume_type,
                                       mock_api_req):

        # prepare the input test data
        fake_new_type = {'id': 'fake-new-type-id'}
        fake_volume_id = self._get_fake_volume_id()

        volume = {
            'id': 'SomeID',
            'provider_id': fake_volume_id
        }

        # configure the mocks with respective side-effects
        mock_api_req.side_effect = self._side_effect_api_req
        get_qos_spec.side_effect = self._fake_get_qos_spec
        get_volume_type.side_effect = self._fake_get_volume_type
        mock_api_req.side_effect = self._fake_api_req_to_list_filesystem

        # Now run the test & assert the exception
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.retype,
                          self.ctxt, volume, fake_new_type, None, None)
