# Copyright (c) 2014 Hitachi Data Systems, 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
import os
import paramiko
import time

from oslo_concurrency import processutils as putils

from cinder import exception
from cinder import test
from cinder import utils
from cinder.volume.drivers.hitachi import hnas_backend


evsfs_list = "\n\
FS ID        FS Label        FS Permanent ID     EVS ID     EVS Label\n\
-----     -----------     ------------------     ------     ---------\n\
 1026            gold     0xaadee0e035cfc0b7          1      EVS-Manila\n\
 1029        test_hdp     0xaadee09634acfcac          1      EVS-Manila\n\
 1030       fs-cinder     0xaadfcf742fba644e          2      EVS-Cinder\n\
 1031         cinder2     0xaadfcf7e0769a6bc          3      EVS-Test\n\
 1024      fs02-husvm     0xaac8715e2e9406cd          3      EVS-Test\n\
\n"

cluster_getmac = "cluster MAC: 83-68-96-AA-DA-5D"

version = "\n\
Model: HNAS 4040                                             \n\n\
Software: 11.2.3319.14 (built 2013-09-19 12:34:24+01:00)     \n\n\
Hardware: NAS Platform (M2SEKW1339109)                       \n\n\
board        MMB1                                            \n\
mmb          11.2.3319.14 release (2013-09-19 12:34:24+01:00)\n\n\
board        MFB1                                            \n\
mfb1hw       MB v0883 WL v002F TD v002F FD v002F TC v0059      \
    RY v0059 TY v0059 IC v0059 WF v00E2 FS v00E2 OS v00E2      \
    WD v00E2 DI v001A FC v0002                               \n\
Serial no    B1339745 (Thu Jan  1 00:00:50 2009)             \n\n\
board        MCP                                             \n\
Serial no    B1339109 (Thu Jan  1 00:00:49 2009)             \n\
\n"

evsipaddr = "\n\
EVS Type    Label            IP Address          Mask             Port  \n\
----------  ---------------  ------------------  ---------------  ------\n\
admin       hnas4040         192.0.2.2           255.255.255.0    eth1  \n\
admin       hnas4040         172.24.44.15        255.255.255.0    eth0  \n\
evs 1       EVSTest1         172.24.44.20        255.255.255.0    ag1   \n\
evs 1       EVSTest1         10.0.0.20           255.255.255.0    ag1   \n\
evs 2       EVSTest2         172.24.44.21        255.255.255.0    ag1   \n\
\n"

df_f = "\n\
ID       Label   EVS    Size          Used  Snapshots  Deduped         Avail  \
Thin  ThinSize  ThinAvail               FS Type\n\
----  ---------- ---  ------  ------------  ---------  -------  ------------  \
----  --------  ---------  --------------------\n\
1025  fs-cinder   2  250 GB  21.4 GB (9%)   0 B (0%)       NA  228 GB (91%)  \
  No                       32 KB,WFS-2,128 DSBs\n\
\n"

df_f_tb = "\n\
ID       Label   EVS    Size          Used  Snapshots  Deduped         Avail  \
Thin  ThinSize  ThinAvail               FS Type\n\
----  ---------- ---  ------  ------------  ---------  -------  ------------  \
----  --------  ---------  --------------------\n\
1025  fs-cinder   2  250 TB  21.4 TB (9%)   0 B (0%)       NA  228 TB (91%)  \
  No                       32 KB,WFS-2,128 DSBs\n\
\n"

nfs_export = "\n\
Export name: /export01-husvm                \n\
Export path: /export01-husvm                \n\
File system label: fs-cinder                \n\
File system size: 250 GB                    \n\
File system free space: 228 GB              \n\
File system state:                          \n\
formatted = Yes                             \n\
mounted = Yes                               \n\
failed = No                                 \n\
thin provisioned = No                       \n\
Access snapshots: Yes                       \n\
Display snapshots: Yes                      \n\
Read Caching: Disabled                      \n\
Disaster recovery setting:                  \n\
Recovered = No                              \n\
Transfer setting = Use file system default  \n\n\
Export configuration:                       \n\
127.0.0.1                                   \n\
\n"

iscsi_one_target = "\n\
Alias               : cinder-default                                  \n\
Globally unique name: iqn.2014-12.10.10.10.10:evstest1.cinder-default \n\
Comment             :                                                 \n\
Secret              : pxr6U37LZZJBoMc                                 \n\
Authentication      : Enabled                                         \n\
Logical units       : No logical units.                               \n\
\n\
  LUN   Logical Unit                                                  \n\
  ----  --------------------------------                              \n\
  0     cinder-lu                                                     \n\
  1     volume-99da7ae7-1e7f-4d57-8bf...                              \n\
\n\
Access configuration:                                                 \n\
"

df_f_single_evs = "\n\
ID       Label      Size          Used  Snapshots  Deduped         Avail  \
Thin  ThinSize  ThinAvail               FS Type\n\
----  ----------  ------  ------------  ---------  -------  ------------  \
----  --------  ---------  --------------------\n\
1025  fs-cinder  250 GB  21.4 GB (9%)   0 B (0%)       NA  228 GB (91%)  \
  No                       32 KB,WFS-2,128 DSBs\n\
\n"

nfs_export_tb = "\n\
Export name: /export01-husvm                \n\
Export path: /export01-husvm                \n\
File system label: fs-cinder                \n\
File system size: 250 TB                    \n\
File system free space: 228 TB              \n\
\n"

nfs_export_not_available = "\n\
Export name: /export01-husvm                \n\
Export path: /export01-husvm                \n\
File system label: fs-cinder                \n\
        *** not available ***               \n\
\n"

evs_list = "\n\
Node EVS ID    Type           Label Enabled Status          IP Address Port \n\
---- ------ ------- --------------- ------- ------ ------------------- ---- \n\
   1        Cluster        hnas4040     Yes Online     192.0.2.200     eth1 \n\
   1      0   Admin        hnas4040     Yes Online       192.0.2.2     eth1 \n\
                                                      172.24.44.15     eth0 \n\
                                                     172.24.49.101      ag2 \n\
   1      1 Service      EVS-Manila     Yes Online    172.24.49.32      ag2 \n\
                                                      172.24.48.32      ag4 \n\
   1      2 Service      EVS-Cinder     Yes Online    172.24.49.21      ag2 \n\
   1      3 Service        EVS-Test     Yes Online 192.168.100.100      ag2 \n\
\n"

iscsilu_list = "Name   : cinder-lu    \n\
Comment:                              \n\
Path   : /.cinder/cinder-lu.iscsi     \n\
Size   : 2 GB                         \n\
File System : fs-cinder               \n\
File System Mounted : YES             \n\
Logical Unit Mounted: No"

iscsilu_list_tb = "Name   : test-lu   \n\
Comment:                              \n\
Path   : /.cinder/test-lu.iscsi     \n\
Size   : 2 TB                         \n\
File System : fs-cinder               \n\
File System Mounted : YES             \n\
Logical Unit Mounted: No"

hnas_fs_list = "%(l1)s\n\n%(l2)s\n\n " % {'l1': iscsilu_list,
                                          'l2': iscsilu_list_tb}

add_targetsecret = "Target created successfully."

iscsi_target_list = "\n\
Alias               : cinder-GoldIsh\n\
Globally unique name: iqn.2015-06.10.10.10.10:evstest1.cinder-goldish\n\
Comment             :\n\
Secret              : None\n\
Authentication      : Enabled\n\
Logical units       : No logical units.\n\
Access configuration :\n\
\n\
Alias               : cinder-default\n\
Globally unique name: iqn.2014-12.10.10.10.10:evstest1.cinder-default\n\
Comment             :\n\
Secret              : pxr6U37LZZJBoMc\n\
Authentication      : Enabled\n\
Logical units       : Logical units       :\n\
\n\
  LUN   Logical Unit\n\
  ----  --------------------------------\n\
  0     cinder-lu\n\
  1     volume-99da7ae7-1e7f-4d57-8bf...\n\
\n\
Access configuration :\n\
"

backend_opts = {'mgmt_ip0': '0.0.0.0',
                'cluster_admin_ip0': None,
                'ssh_port': '22',
                'username': 'supervisor',
                'password': 'supervisor',
                'ssh_private_key': 'test_key'}

target_chap_disable = "\n\
Alias               : cinder-default                                  \n\
Globally unique name: iqn.2014-12.10.10.10.10:evstest1.cinder-default \n\
Comment             :                                                 \n\
Secret              :                                                 \n\
Authentication      : Disabled                                        \n\
Logical units       : No logical units.                               \n\
\n\
  LUN   Logical Unit                                                  \n\
  ----  --------------------------------                              \n\
  0     cinder-lu                                                     \n\
  1     volume-99da7ae7-1e7f-4d57-8bf...                              \n\
\n\
Access configuration:                                                 \n\
"

file_clone_stat = "Clone: /nfs_cinder/cinder-lu                      \n\
  SnapshotFile: FileHandle[00000000004010000d20116826ffffffffffffff] \n\
\n\
  SnapshotFile: FileHandle[00000000004029000d81f26826ffffffffffffff] \n\
"

file_clone_stat_snap_file1 = "\
FileHandle[00000000004010000d20116826ffffffffffffff]                  \n\n\
References:                                                           \n\
  Clone: /nfs_cinder/cinder-lu                                        \n\
  Clone: /nfs_cinder/snapshot-lu-1                                    \n\
  Clone: /nfs_cinder/snapshot-lu-2                                    \n\
"

file_clone_stat_snap_file2 = "\
FileHandle[00000000004010000d20116826ffffffffffffff]                  \n\n\
References:                                                           \n\
  Clone: /nfs_cinder/volume-not-used                                  \n\
  Clone: /nfs_cinder/snapshot-1                                       \n\
  Clone: /nfs_cinder/snapshot-2                                       \n\
"

not_a_clone = "\
file-clone-stat: failed to get predecessor snapshot-files: File is not a clone"


class HDSHNASBackendTest(test.TestCase):

    def __init__(self, *args, **kwargs):
        super(HDSHNASBackendTest, self).__init__(*args, **kwargs)

    def setUp(self):
        super(HDSHNASBackendTest, self).setUp()
        self.hnas_backend = hnas_backend.HNASSSHBackend(backend_opts)

    def test_run_cmd(self):
        self.mock_object(os.path, 'isfile',
                         mock.Mock(return_value=True))
        self.mock_object(utils, 'execute')
        self.mock_object(time, 'sleep')
        self.mock_object(paramiko, 'SSHClient')
        self.mock_object(paramiko.RSAKey, 'from_private_key_file')
        self.mock_object(putils, 'ssh_execute',
                         mock.Mock(return_value=(df_f, '')))

        out, err = self.hnas_backend._run_cmd('ssh', '0.0.0.0',
                                              'supervisor', 'supervisor',
                                              'df', '-a')

        self.assertIn('fs-cinder', out)
        self.assertIn('WFS-2,128 DSBs', out)

    def test_run_cmd_retry_exception(self):
        self.hnas_backend.cluster_admin_ip0 = '172.24.44.11'

        exceptions = [putils.ProcessExecutionError(stderr='Connection reset'),
                      putils.ProcessExecutionError(stderr='Failed to establish'
                                                          ' SSC connection'),
                      putils.ProcessExecutionError(stderr='Connection reset'),
                      putils.ProcessExecutionError(stderr='Connection reset'),
                      putils.ProcessExecutionError(stderr='Connection reset')]

        self.mock_object(os.path, 'isfile',
                         mock.Mock(return_value=True))
        self.mock_object(utils, 'execute')
        self.mock_object(time, 'sleep')
        self.mock_object(paramiko, 'SSHClient')
        self.mock_object(paramiko.RSAKey, 'from_private_key_file')
        self.mock_object(putils, 'ssh_execute',
                         mock.Mock(side_effect=exceptions))

        self.assertRaises(exception.HNASConnError, self.hnas_backend._run_cmd,
                          'ssh', '0.0.0.0', 'supervisor', 'supervisor', 'df',
                          '-a')

    def test_run_cmd_exception_without_retry(self):
        self.mock_object(os.path, 'isfile',
                         mock.Mock(return_value=True))
        self.mock_object(utils, 'execute')
        self.mock_object(time, 'sleep')
        self.mock_object(paramiko, 'SSHClient')
        self.mock_object(paramiko.RSAKey, 'from_private_key_file')
        self.mock_object(putils, 'ssh_execute',
                         mock.Mock(side_effect=putils.ProcessExecutionError
                                   (stderr='Error')))

        self.assertRaises(putils.ProcessExecutionError,
                          self.hnas_backend._run_cmd, 'ssh', '0.0.0.0',
                          'supervisor', 'supervisor', 'df', '-a')

    def test_get_targets_empty_list(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=('No targets', '')))

        out = self.hnas_backend._get_targets('2')
        self.assertEqual([], out)

    def test_get_targets_not_found(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(iscsi_target_list, '')))

        out = self.hnas_backend._get_targets('2', 'fake-volume')
        self.assertEqual([], out)

    def test__get_unused_luid_number_0(self):
        tgt_info = {
            'alias': 'cinder-default',
            'secret': 'pxr6U37LZZJBoMc',
            'iqn': 'iqn.2014-12.10.10.10.10:evstest1.cinder-default',
            'lus': [
                {'id': '1',
                 'name': 'cinder-lu2'},
                {'id': '2',
                 'name': 'volume-test2'}
            ],
            'auth': 'Enabled'
        }

        out = self.hnas_backend._get_unused_luid(tgt_info)

        self.assertEqual(0, out)

    def test__get_unused_no_luns(self):
        tgt_info = {
            'alias': 'cinder-default',
            'secret': 'pxr6U37LZZJBoMc',
            'iqn': 'iqn.2014-12.10.10.10.10:evstest1.cinder-default',
            'lus': [],
            'auth': 'Enabled'
        }

        out = self.hnas_backend._get_unused_luid(tgt_info)

        self.assertEqual(0, out)

    def test_get_version(self):
        expected_out = {
            'hardware': 'NAS Platform (M2SEKW1339109)',
            'mac': '83-68-96-AA-DA-5D',
            'version': '11.2.3319.14',
            'model': 'HNAS 4040',
            'serial': 'B1339745'
        }

        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[
                             (cluster_getmac, ''),
                             (version, '')]))

        out = self.hnas_backend.get_version()

        self.assertEqual(expected_out, out)

    def test_get_evs(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))

        out = self.hnas_backend.get_evs('fs-cinder')

        self.assertEqual('2', out)

    def test_get_export_list(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(nfs_export, ''),
                                                (evsfs_list, ''),
                                                (evs_list, '')]))

        out = self.hnas_backend.get_export_list()

        self.assertEqual('fs-cinder', out[0]['fs'])
        self.assertEqual(250.0, out[0]['size'])
        self.assertEqual(228.0, out[0]['free'])
        self.assertEqual('/export01-husvm', out[0]['path'])

    def test_get_export_list_data_not_available(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(nfs_export_not_available, ''),
                                                (evsfs_list, ''),
                                                (evs_list, '')]))

        out = self.hnas_backend.get_export_list()

        self.assertEqual('fs-cinder', out[0]['fs'])
        self.assertEqual('/export01-husvm', out[0]['path'])
        self.assertEqual(-1, out[0]['size'])
        self.assertEqual(-1, out[0]['free'])

    def test_get_export_list_tb(self):
        size = float(250 * 1024)
        free = float(228 * 1024)
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(nfs_export_tb, ''),
                                                (evsfs_list, ''),
                                                (evs_list, '')]))

        out = self.hnas_backend.get_export_list()

        self.assertEqual('fs-cinder', out[0]['fs'])
        self.assertEqual(size, out[0]['size'])
        self.assertEqual(free, out[0]['free'])
        self.assertEqual('/export01-husvm', out[0]['path'])

    def test_file_clone(self):
        path1 = '/.cinder/path1'
        path2 = '/.cinder/path2'

        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))

        self.hnas_backend.file_clone('fs-cinder', path1, path2)

        calls = [mock.call('evsfs', 'list'), mock.call('console-context',
                                                       '--evs', '2',
                                                       'file-clone-create',
                                                       '-f', 'fs-cinder',
                                                       path1, path2)]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_file_clone_wrong_fs(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))

        self.assertRaises(exception.InvalidParameterValue,
                          self.hnas_backend.file_clone, 'fs-fake', 'src',
                          'dst')

    def test_get_evs_info(self):
        expected_out = {'evs_number': '1'}
        expected_out2 = {'evs_number': '2'}

        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsipaddr, '')))

        out = self.hnas_backend.get_evs_info()

        self.hnas_backend._run_cmd.assert_called_with('evsipaddr', '-l')
        self.assertEqual(expected_out, out['10.0.0.20'])
        self.assertEqual(expected_out, out['172.24.44.20'])
        self.assertEqual(expected_out2, out['172.24.44.21'])

    def test_get_fs_info(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(df_f, ''),
                                                (evsfs_list, ''),
                                                (hnas_fs_list, '')]))

        out = self.hnas_backend.get_fs_info('fs-cinder')

        self.assertEqual('2', out['evs_id'])
        self.assertEqual('fs-cinder', out['label'])
        self.assertEqual('228', out['available_size'])
        self.assertEqual('250', out['total_size'])
        self.assertEqual(2050.0, out['provisioned_capacity'])

    def test_get_fs_empty_return(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=('Not mounted', '')))

        out = self.hnas_backend.get_fs_info('fs-cinder')
        self.assertEqual({}, out)

    def test_get_fs_info_single_evs(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(df_f_single_evs, ''),
                                                (evsfs_list, ''),
                                                (hnas_fs_list, '')]))

        out = self.hnas_backend.get_fs_info('fs-cinder')

        self.assertEqual('fs-cinder', out['label'])
        self.assertEqual('228', out['available_size'])
        self.assertEqual('250', out['total_size'])
        self.assertEqual(2050.0, out['provisioned_capacity'])

    def test_get_fs_tb(self):
        available_size = float(228 * 1024 ** 2)
        total_size = float(250 * 1024 ** 2)

        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(df_f_tb, ''),
                                                (evsfs_list, ''),
                                                (hnas_fs_list, '')]))

        out = self.hnas_backend.get_fs_info('fs-cinder')

        self.assertEqual('fs-cinder', out['label'])
        self.assertEqual(str(available_size), out['available_size'])
        self.assertEqual(str(total_size), out['total_size'])
        self.assertEqual(2050.0, out['provisioned_capacity'])

    def test_get_fs_single_evs_tb(self):
        available_size = float(228 * 1024 ** 2)
        total_size = float(250 * 1024 ** 2)

        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(df_f_tb, ''),
                                                (evsfs_list, ''),
                                                (hnas_fs_list, '')]))

        out = self.hnas_backend.get_fs_info('fs-cinder')

        self.assertEqual('fs-cinder', out['label'])
        self.assertEqual(str(available_size), out['available_size'])
        self.assertEqual(str(total_size), out['total_size'])
        self.assertEqual(2050.0, out['provisioned_capacity'])

    def test_create_lu(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))

        self.hnas_backend.create_lu('fs-cinder', '128', 'cinder-lu')

        calls = [mock.call('evsfs', 'list'), mock.call('console-context',
                                                       '--evs', '2',
                                                       'iscsi-lu', 'add',
                                                       '-e', 'cinder-lu',
                                                       'fs-cinder',
                                                       '/.cinder/cinder-lu.'
                                                       'iscsi', '128G')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_delete_lu(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))

        self.hnas_backend.delete_lu('fs-cinder', 'cinder-lu')

        calls = [mock.call('evsfs', 'list'), mock.call('console-context',
                                                       '--evs', '2',
                                                       'iscsi-lu', 'del', '-d',
                                                       '-f', 'cinder-lu')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_extend_lu(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))

        self.hnas_backend.extend_lu('fs-cinder', '128', 'cinder-lu')

        calls = [mock.call('evsfs', 'list'), mock.call('console-context',
                                                       '--evs', '2',
                                                       'iscsi-lu', 'expand',
                                                       'cinder-lu', '128G')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_cloned_lu(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))

        self.hnas_backend.create_cloned_lu('cinder-lu', 'fs-cinder', 'snap')

        calls = [mock.call('evsfs', 'list'), mock.call('console-context',
                                                       '--evs', '2',
                                                       'iscsi-lu', 'clone',
                                                       '-e', 'cinder-lu',
                                                       'snap',
                                                       '/.cinder/snap.iscsi')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_get_existing_lu_info(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsilu_list, '')]))

        out = self.hnas_backend.get_existing_lu_info('cinder-lu', None, None)

        self.assertEqual('cinder-lu', out['name'])
        self.assertEqual('fs-cinder', out['filesystem'])
        self.assertEqual(2.0, out['size'])

    def test_get_existing_lu_info_tb(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsilu_list_tb, '')]))

        out = self.hnas_backend.get_existing_lu_info('test-lu', None, None)

        self.assertEqual('test-lu', out['name'])
        self.assertEqual('fs-cinder', out['filesystem'])
        self.assertEqual(2048.0, out['size'])

    def test_rename_existing_lu(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))
        self.hnas_backend.rename_existing_lu('fs-cinder', 'cinder-lu',
                                             'new-lu-name')

        calls = [mock.call('evsfs', 'list'), mock.call('console-context',
                                                       '--evs', '2',
                                                       'iscsi-lu', 'mod', '-n',
                                                       "'new-lu-name'",
                                                       'cinder-lu')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_check_lu(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsi_target_list, '')]))

        out = self.hnas_backend.check_lu('cinder-lu', 'fs-cinder')

        self.assertEqual('cinder-lu', out['tgt']['lus'][0]['name'])
        self.assertEqual('pxr6U37LZZJBoMc', out['tgt']['secret'])
        self.assertTrue(out['mapped'])
        calls = [mock.call('evsfs', 'list'), mock.call('console-context',
                                                       '--evs', '2',
                                                       'iscsi-target', 'list')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_check_lu_not_found(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsi_target_list, '')]))

        # passing a volume fake-volume not mapped
        out = self.hnas_backend.check_lu('fake-volume', 'fs-cinder')
        self.assertFalse(out['mapped'])
        self.assertEqual(0, out['id'])
        self.assertIsNone(out['tgt'])

    def test_add_iscsi_conn(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsi_target_list, ''),
                                                (evsfs_list, '')]))

        out = self.hnas_backend.add_iscsi_conn('cinder-lu', 'fs-cinder', 3260,
                                               'cinder-default', 'initiator')

        self.assertEqual('cinder-lu', out['lu_name'])
        self.assertEqual('fs-cinder', out['fs'])
        self.assertEqual('0', out['lu_id'])
        self.assertEqual(3260, out['port'])
        calls = [mock.call('evsfs', 'list'),
                 mock.call('console-context', '--evs', '2', 'iscsi-target',
                           'list')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_add_iscsi_conn_not_mapped_volume(self):
        not_mapped = {'mapped': False,
                      'id': 0,
                      'tgt': None}

        self.mock_object(self.hnas_backend, 'check_lu',
                         mock.Mock(return_value=not_mapped))
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsi_target_list, ''),
                                                ('', '')]))

        out = self.hnas_backend.add_iscsi_conn('cinder-lu', 'fs-cinder', 3260,
                                               'cinder-default', 'initiator')

        self.assertEqual('cinder-lu', out['lu_name'])
        self.assertEqual('fs-cinder', out['fs'])
        self.assertEqual(2, out['lu_id'])
        self.assertEqual(3260, out['port'])
        calls = [mock.call('evsfs', 'list'),
                 mock.call('console-context', '--evs', '2', 'iscsi-target',
                           'list')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_del_iscsi_conn(self):
        iqn = 'iqn.2014-12.10.10.10.10:evstest1.cinder-default'

        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(iscsi_one_target, '')))

        self.hnas_backend.del_iscsi_conn('2', iqn, '0')

        calls = [mock.call('console-context', '--evs', '2', 'iscsi-target',
                           'list', iqn),
                 mock.call('console-context', '--evs', '2', 'iscsi-target',
                           'dellu', '-f', iqn, '0')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_del_iscsi_conn_volume_not_found(self):
        iqn = 'iqn.2014-12.10.10.10.10:evstest1.cinder-fake'

        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(iscsi_one_target, '')))

        self.hnas_backend.del_iscsi_conn('2', iqn, '10')

        self.hnas_backend._run_cmd.assert_called_with('console-context',
                                                      '--evs', '2',
                                                      'iscsi-target', 'list',
                                                      iqn)

    def test_check_target(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsi_target_list, '')]))

        out = self.hnas_backend.check_target('fs-cinder', 'cinder-default')

        self.assertTrue(out['found'])
        self.assertEqual('cinder-lu', out['tgt']['lus'][0]['name'])
        self.assertEqual('cinder-default', out['tgt']['alias'])
        self.assertEqual('pxr6U37LZZJBoMc', out['tgt']['secret'])

    def test_check_target_not_found(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsi_target_list, '')]))

        out = self.hnas_backend.check_target('fs-cinder', 'cinder-fake')

        self.assertFalse(out['found'])
        self.assertIsNone(out['tgt'])

    def test_set_target_secret(self):
        targetalias = 'cinder-default'
        secret = 'pxr6U37LZZJBoMc'
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))

        self.hnas_backend.set_target_secret(targetalias, 'fs-cinder', secret)

        calls = [mock.call('evsfs', 'list'),
                 mock.call('console-context', '--evs', '2', 'iscsi-target',
                           'mod', '-s', 'pxr6U37LZZJBoMc', '-a', 'enable',
                           'cinder-default')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_set_target_secret_empty_target_list(self):
        targetalias = 'cinder-default'
        secret = 'pxr6U37LZZJBoMc'

        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                ('does not exist', ''),
                                                ('', '')]))

        self.hnas_backend.set_target_secret(targetalias, 'fs-cinder', secret)

        calls = [mock.call('console-context', '--evs', '2', 'iscsi-target',
                           'mod', '-s', 'pxr6U37LZZJBoMc', '-a', 'enable',
                           'cinder-default')]
        self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)

    def test_get_target_secret(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsi_one_target, '')]))
        out = self.hnas_backend.get_target_secret('cinder-default',
                                                  'fs-cinder')

        self.assertEqual('pxr6U37LZZJBoMc', out)

        self.hnas_backend._run_cmd.assert_called_with('console-context',
                                                      '--evs', '2',
                                                      'iscsi-target', 'list',
                                                      'cinder-default')

    def test_get_target_secret_chap_disabled(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (target_chap_disable, '')]))
        out = self.hnas_backend.get_target_secret('cinder-default',
                                                  'fs-cinder')

        self.assertEqual('', out)

        self.hnas_backend._run_cmd.assert_called_with('console-context',
                                                      '--evs', '2',
                                                      'iscsi-target', 'list',
                                                      'cinder-default')

    def test_get_target_iqn(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (iscsi_one_target, ''),
                                                (add_targetsecret, '')]))

        out = self.hnas_backend.get_target_iqn('cinder-default', 'fs-cinder')

        self.assertEqual('iqn.2014-12.10.10.10.10:evstest1.cinder-default',
                         out)

    def test_create_target(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(return_value=(evsfs_list, '')))

        self.hnas_backend.create_target('cinder-default', 'fs-cinder',
                                        'pxr6U37LZZJBoMc')

    def test_check_snapshot_parent_true(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(
                             side_effect=[(evsfs_list, ''),
                                          (file_clone_stat, ''),
                                          (file_clone_stat_snap_file1, ''),
                                          (file_clone_stat_snap_file2, '')]))
        out = self.hnas_backend.check_snapshot_parent('cinder-lu',
                                                      'snapshot-lu-1',
                                                      'fs-cinder')

        self.assertTrue(out)
        self.hnas_backend._run_cmd.assert_called_with('console-context',
                                                      '--evs', '2',
                                                      'file-clone-stat'
                                                      '-snapshot-file', '-f',
                                                      'fs-cinder',
                                                      '00000000004010000d2011'
                                                      '6826ffffffffffffff]')

    def test_check_snapshot_parent_false(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(
                             side_effect=[(evsfs_list, ''),
                                          (file_clone_stat, ''),
                                          (file_clone_stat_snap_file1, ''),
                                          (file_clone_stat_snap_file2, '')]))
        out = self.hnas_backend.check_snapshot_parent('cinder-lu',
                                                      'snapshot-lu-3',
                                                      'fs-cinder')

        self.assertFalse(out)
        self.hnas_backend._run_cmd.assert_called_with('console-context',
                                                      '--evs', '2',
                                                      'file-clone-stat'
                                                      '-snapshot-file', '-f',
                                                      'fs-cinder',
                                                      '00000000004029000d81f26'
                                                      '826ffffffffffffff]')

    def test_check_a_not_cloned_file(self):
        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(
                             side_effect=[(evsfs_list, ''),
                                          (not_a_clone, '')]))

        self.assertRaises(exception.ManageExistingInvalidReference,
                          self.hnas_backend.check_snapshot_parent,
                          'cinder-lu', 'snapshot-name', 'fs-cinder')

    def test_get_export_path(self):
        export_out = '/export01-husvm'

        self.mock_object(self.hnas_backend, '_run_cmd',
                         mock.Mock(side_effect=[(evsfs_list, ''),
                                                (nfs_export, '')]))

        out = self.hnas_backend.get_export_path(export_out, 'fs-cinder')

        self.assertEqual(export_out, out)
        self.hnas_backend._run_cmd.assert_called_with('console-context',
                                                      '--evs', '2',
                                                      'nfs-export', 'list',
                                                      export_out)
