# Copyright (c) 2023 NetApp, 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 math
import time
from unittest import mock

import ddt
from oslo_log import log
from oslo_utils import netutils
from oslo_utils import units

from manila import exception
from manila.share.drivers.netapp.dataontap.client import client_cmode
from manila.share.drivers.netapp.dataontap.client import client_cmode_rest
from manila.share.drivers.netapp.dataontap.client import rest_api as netapp_api
from manila.share.drivers.netapp import utils as netapp_utils
from manila import test
from manila.tests.share.drivers.netapp.dataontap.client import fakes as fake
from manila import utils


@ddt.ddt
class NetAppRestCmodeClientTestCase(test.TestCase):

    def setUp(self):
        super(NetAppRestCmodeClientTestCase, self).setUp()

        # Mock loggers as themselves to allow logger arg validation
        mock_logger = log.getLogger('mock_logger')
        self.mock_object(client_cmode_rest.LOG,
                         'error',
                         mock.Mock(side_effect=mock_logger.error))
        self.mock_object(client_cmode_rest.LOG,
                         'warning',
                         mock.Mock(side_effect=mock_logger.warning))
        self.mock_object(client_cmode_rest.LOG,
                         'debug',
                         mock.Mock(side_effect=mock_logger.debug))
        self.mock_object(client_cmode.NetAppCmodeClient,
                         'get_ontapi_version',
                         mock.Mock(return_value=(1, 20)))
        # store the original reference so we can call it later in
        # test_get_ontap_version
        self.original_get_ontap_version = (
            client_cmode_rest.NetAppRestClient.get_ontap_version)
        self.mock_object(client_cmode_rest.NetAppRestClient,
                         'get_ontap_version',
                         mock.Mock(return_value={
                             'version-tuple': (9, 12, 1),
                             'version': fake.VERSION,
                         }))
        self.original_check_for_cluster_credentials = (
            client_cmode_rest.NetAppRestClient._check_for_cluster_credentials)
        self.mock_object(client_cmode_rest.NetAppRestClient,
                         '_check_for_cluster_credentials',
                         mock.Mock(return_value=True))
        self.mock_object(client_cmode.NetAppCmodeClient,
                         'get_system_version',
                         mock.Mock(return_value={
                             'version-tuple': (9, 10, 1),
                             'version': fake.VERSION,
                         }))

        self.client = client_cmode_rest.NetAppRestClient(
            **fake.CONNECTION_INFO)
        self.client.connection = mock.MagicMock()

        self.sleep_patcher = mock.patch.object(time, 'sleep', lambda s: None)
        self.sleep_patcher.start()
        self.addCleanup(self.sleep_patcher.stop)

    def _mock_api_error(self, code='fake', message='fake'):
        return mock.Mock(
            side_effect=netapp_api.api.NaApiError(code=code, message=message))

    def test_send_request(self):
        expected = 'fake_response'
        mock_get_records = self.mock_object(
            self.client, 'get_records',
            mock.Mock(return_value=expected))

        res = self.client.send_request(
            fake.FAKE_ACTION_URL, 'get',
            body=fake.FAKE_HTTP_BODY,
            query=fake.FAKE_HTTP_QUERY, enable_tunneling=False)

        self.assertEqual(expected, res)
        mock_get_records.assert_called_once_with(
            fake.FAKE_ACTION_URL,
            fake.FAKE_HTTP_QUERY, False, 10000)

    def test_send_request_post(self):
        expected = (201, 'fake_response')
        mock_invoke = self.mock_object(
            self.client.connection, 'invoke_successfully',
            mock.Mock(return_value=expected))

        res = self.client.send_request(
            fake.FAKE_ACTION_URL, 'post',
            body=fake.FAKE_HTTP_BODY,
            query=fake.FAKE_HTTP_QUERY, enable_tunneling=False)

        self.assertEqual(expected[1], res)
        mock_invoke.assert_called_once_with(
            fake.FAKE_ACTION_URL, 'post',
            body=fake.FAKE_HTTP_BODY,
            query=fake.FAKE_HTTP_QUERY, enable_tunneling=False)

    def test_send_request_wait(self):
        expected = (202, fake.JOB_RESPONSE_REST)
        mock_invoke = self.mock_object(
            self.client.connection, 'invoke_successfully',
            mock.Mock(return_value=expected))

        mock_wait = self.mock_object(
            self.client, '_wait_job_result',
            mock.Mock(return_value=expected[1]))

        res = self.client.send_request(
            fake.FAKE_ACTION_URL, 'post',
            body=fake.FAKE_HTTP_BODY,
            query=fake.FAKE_HTTP_QUERY, enable_tunneling=False)

        self.assertEqual(expected[1], res)
        mock_invoke.assert_called_once_with(
            fake.FAKE_ACTION_URL, 'post',
            body=fake.FAKE_HTTP_BODY,
            query=fake.FAKE_HTTP_QUERY, enable_tunneling=False)
        mock_wait.assert_called_once_with(
            expected[1]['job']['_links']['self']['href'][4:])

    @ddt.data(True, False)
    def test_get_records(self, enable_tunneling):
        api_responses = [
            (200, fake.VOLUME_GET_ITER_RESPONSE_REST_PAGE),
            (200, fake.VOLUME_GET_ITER_RESPONSE_REST_PAGE),
            (200, fake.VOLUME_GET_ITER_RESPONSE_REST_LAST_PAGE),
        ]

        mock_invoke = self.mock_object(
            self.client.connection, 'invoke_successfully',
            mock.Mock(side_effect=copy.deepcopy(api_responses)))

        query = {
            'fields': 'name'
        }

        result = self.client.get_records(
            '/storage/volumes/', query=query,
            enable_tunneling=enable_tunneling,
            max_page_length=10)

        num_records = result['num_records']
        self.assertEqual(28, num_records)
        self.assertEqual(28, len(result['records']))

        expected_records = []
        expected_records.extend(api_responses[0][1]['records'])
        expected_records.extend(api_responses[1][1]['records'])
        expected_records.extend(api_responses[2][1]['records'])

        self.assertEqual(expected_records, result['records'])

        next_tag = result.get('next')
        self.assertIsNone(next_tag)

        expected_query = copy.deepcopy(query)
        expected_query['max_records'] = 10

        next_url_1 = api_responses[0][1]['_links']['next']['href'][4:]
        next_url_2 = api_responses[1][1]['_links']['next']['href'][4:]

        mock_invoke.assert_has_calls([
            mock.call('/storage/volumes/', 'get', query=expected_query,
                      enable_tunneling=enable_tunneling),
            mock.call(next_url_1, 'get', query=None,
                      enable_tunneling=enable_tunneling),
            mock.call(next_url_2, 'get', query=None,
                      enable_tunneling=enable_tunneling),
        ])

    def test_get_records_single_page(self):

        api_response = (
            200, fake.VOLUME_GET_ITER_RESPONSE_REST_LAST_PAGE)
        mock_invoke = self.mock_object(self.client.connection,
                                       'invoke_successfully',
                                       mock.Mock(return_value=api_response))

        query = {
            'fields': 'name'
        }

        result = self.client.get_records(
            '/storage/volumes/', query=query, max_page_length=10)

        num_records = result['num_records']
        self.assertEqual(8, num_records)
        self.assertEqual(8, len(result['records']))

        next_tag = result.get('next')
        self.assertIsNone(next_tag)

        args = copy.deepcopy(query)
        args['max_records'] = 10

        mock_invoke.assert_has_calls([
            mock.call('/storage/volumes/', 'get', query=args,
                      enable_tunneling=True),
        ])

    def test_get_records_not_found(self):

        api_response = (200, fake.NO_RECORDS_RESPONSE_REST)
        mock_invoke = self.mock_object(self.client.connection,
                                       'invoke_successfully',
                                       mock.Mock(return_value=api_response))

        result = self.client.get_records('/storage/volumes/')

        num_records = result['num_records']
        self.assertEqual(0, num_records)
        self.assertEqual(0, len(result['records']))

        args = {
            'max_records': client_cmode_rest.DEFAULT_MAX_PAGE_LENGTH
        }

        mock_invoke.assert_has_calls([
            mock.call('/storage/volumes/', 'get', query=args,
                      enable_tunneling=True),
        ])

    def test_get_records_timeout(self):
        # To simulate timeout, max_records is 30, but the API returns less
        # records and fill the 'next url' pointing to the next page.
        max_records = 30
        api_responses = [
            (200, fake.VOLUME_GET_ITER_RESPONSE_REST_PAGE),
            (200, fake.VOLUME_GET_ITER_RESPONSE_REST_PAGE),
            (200, fake.VOLUME_GET_ITER_RESPONSE_REST_LAST_PAGE),
        ]

        mock_invoke = self.mock_object(
            self.client.connection, 'invoke_successfully',
            mock.Mock(side_effect=copy.deepcopy(api_responses)))

        query = {
            'fields': 'name'
        }

        result = self.client.get_records(
            '/storage/volumes/', query=query, max_page_length=max_records)

        num_records = result['num_records']
        self.assertEqual(28, num_records)
        self.assertEqual(28, len(result['records']))

        expected_records = []
        expected_records.extend(api_responses[0][1]['records'])
        expected_records.extend(api_responses[1][1]['records'])
        expected_records.extend(api_responses[2][1]['records'])

        self.assertEqual(expected_records, result['records'])

        next_tag = result.get('next', None)
        self.assertIsNone(next_tag)

        args1 = copy.deepcopy(query)
        args1['max_records'] = max_records

        next_url_1 = api_responses[0][1]['_links']['next']['href'][4:]
        next_url_2 = api_responses[1][1]['_links']['next']['href'][4:]

        mock_invoke.assert_has_calls([
            mock.call('/storage/volumes/', 'get', query=args1,
                      enable_tunneling=True),
            mock.call(next_url_1, 'get', query=None, enable_tunneling=True),
            mock.call(next_url_2, 'get', query=None, enable_tunneling=True),
        ])

    def test__getattr__(self):
        # NOTE(nahimsouza): get_ontapi_version is implemented only in ZAPI
        # client, therefore, it will call __getattr__
        self.client.get_ontapi_version()

    @ddt.data(True, False)
    def test_get_ontap_version(self, cached):
        self.client.get_ontap_version = self.original_get_ontap_version
        api_response = {
            'records': [
                {
                    'version': {
                        'generation': 9,
                        'major': 11,
                        'minor': 1,
                        'full': 'NetApp Release 9.11.1'
                    }
                }]

        }
        return_mock = {
            'version': 'NetApp Release 9.11.1',
            'version-tuple': (9, 11, 1)
        }
        mock_connect = self.mock_object(self.client.connection,
                                        'get_ontap_version',
                                        mock.Mock(return_value=return_mock))
        mock_send_request = self.mock_object(
            self.client,
            'send_request',
            mock.Mock(return_value=api_response))

        result = self.client.get_ontap_version(self=self.client, cached=cached)

        if cached:
            mock_connect.assert_called_once()
        else:
            mock_send_request.assert_called_once_with(
                '/cluster/nodes', 'get', query={'fields': 'version'},
                enable_tunneling=False)

        self.assertEqual(return_mock, result)

    def test__wait_job_result(self):
        response = fake.JOB_SUCCESSFUL_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=response))
        result = self.client._wait_job_result(
            f'/cluster/jobs/{fake.FAKE_UUID}')
        self.assertEqual(response, result)

    def test__wait_job_result_failure(self):
        response = fake.JOB_ERROR_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(netapp_utils.NetAppDriverException,
                          self.client._wait_job_result,
                          f'/cluster/jobs/{fake.FAKE_UUID}')

    def test__wait_job_result_timeout(self):
        response = fake.JOB_RUNNING_REST
        self.client.async_rest_timeout = 2
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(netapp_utils.NetAppDriverException,
                          self.client._wait_job_result,
                          f'/cluster/jobs/{fake.FAKE_UUID}')

    def test_list_cluster_nodes(self):
        """Get all available cluster nodes."""

        return_value = fake.FAKE_GET_CLUSTER_NODE_VERSION_REST

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))
        test_result = self.client.list_cluster_nodes()

        self.client.send_request.assert_called_once_with(
            '/cluster/nodes', 'get'
        )

        nodes = return_value.get('records', [])

        expected_result = [node['name'] for node in nodes]

        self.assertEqual(expected_result, test_result)

    @ddt.data(True, False)
    def test_check_for_cluster_credentials(self, cluster_creds):
        self.client._have_cluster_creds = cluster_creds

        result = self.client.check_for_cluster_credentials()

        self.assertEqual(cluster_creds, result)

    def test__check_for_cluster_credentials(self):
        self.client._check_for_cluster_credentials = (
            self.original_check_for_cluster_credentials)
        api_response = fake.FAKE_GET_CLUSTER_NODE_VERSION_REST
        self.mock_object(self.client,
                         'list_cluster_nodes',
                         mock.Mock(return_value=api_response))

        result = self.client._check_for_cluster_credentials(self=self.client)

        self.assertTrue(result)

    def test__check_for_cluster_credentials_not_cluster(self):
        self.client._check_for_cluster_credentials = (
            self.original_check_for_cluster_credentials)
        self.mock_object(self.client, 'list_cluster_nodes',
                         self._mock_api_error(
                             netapp_api.EREST_NOT_AUTHORIZED))

        result = self.client._check_for_cluster_credentials(self=self.client)

        self.assertFalse(result)

    def test__check_for_cluster_credentials_api_error(self):
        self.client._check_for_cluster_credentials = (
            self.original_check_for_cluster_credentials)
        self.mock_object(self.client, 'list_cluster_nodes',
                         self._mock_api_error())

        self.assertRaises(netapp_api.api.NaApiError,
                          self.client._check_for_cluster_credentials,
                          self.client)

    def test_get_licenses(self):
        return_value = fake.FAKE_GET_LICENSES_REST

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        test_result = self.client.get_licenses()

        expected_result = sorted(
            [license['name'] for license in return_value.get('records', [])])

        self.assertEqual(test_result, expected_result)

    @ddt.data(((9, 1, 0), fake.VERSION_NO_DARE), ((8, 3, 2), fake.VERSION))
    @ddt.unpack
    def test_is_nve_supported_unsupported_release_or_platform(self, gen, ver):
        system_version = {'version-tuple': gen, 'version': ver}
        self.mock_object(self.client,
                         'get_ontap_version',
                         mock.Mock(return_value=system_version))
        self.mock_object(self.client,
                         '_get_security_key_manager_nve_support',
                         mock.Mock(return_value=False))
        self.mock_object(self.client,
                         'list_cluster_nodes',
                         mock.Mock(return_value=fake.NODE_NAMES))

        result = self.client.is_nve_supported()

        self.assertFalse(result)

    def test_is_nve_supported_valid_platform_and_supported_release(self):

        system_version = {
            'version-tuple': (9, 1, 0),
            'version': fake.VERSION,
        }
        self.mock_object(self.client,
                         'get_ontap_version',
                         mock.Mock(return_value=system_version))
        self.mock_object(self.client,
                         '_get_security_key_manager_nve_support',
                         mock.Mock(return_value=True))
        self.mock_object(self.client,
                         'list_cluster_nodes',
                         mock.Mock(return_value=fake.NODE_NAMES))

        result = self.client.is_nve_supported()
        self.assertTrue(result)

    def test_is_nve_supported_key_manager_not_enabled(self):

        system_version = {
            'version-tuple': (9, 1, 0),
            'version': fake.VERSION,
        }
        self.mock_object(self.client,
                         'get_ontap_version',
                         mock.Mock(return_value=system_version))
        self.mock_object(self.client,
                         '_get_security_key_manager_nve_support',
                         mock.Mock(return_value=False))
        self.mock_object(self.client,
                         'list_cluster_nodes',
                         mock.Mock(return_value=fake.NODE_NAMES))

        result = self.client.is_nve_supported()

        self.assertFalse(result)

    def test__get_volume_by_args(self):
        response = fake.VOLUME_LIST_SIMPLE_RESPONSE_REST
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))

        result = self.client._get_volume_by_args(
            vol_name=fake.VOLUME_NAMES[0],
            aggregate_name=fake.SHARE_AGGREGATE_NAME,
            vol_path=fake.VOLUME_JUNCTION_PATH,
            vserver=fake.VSERVER_NAME,
            fields='name,style,svm.name,svm.uuid')

        query = {
            'name': fake.VOLUME_NAMES[0],
            'aggregates.name': fake.SHARE_AGGREGATE_NAME,
            'nas.path': fake.VOLUME_JUNCTION_PATH,
            'svm.name': fake.VSERVER_NAME,
            'style': 'flex*',  # Match both 'flexvol' and 'flexgroup'
            'error_state.is_inconsistent': 'false',
            'fields': 'name,style,svm.name,svm.uuid'
        }
        self.client.send_request.assert_called_once_with(
            '/storage/volumes/', 'get', query=query)

        self.assertEqual(volume, result)

    def test_restore_snapshot(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST["uuid"]
        body = {
            'restore_to.snapshot.name': fake.SNAPSHOT_NAME
        }

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.client.restore_snapshot(fake.VOLUME_NAMES[0], fake.SNAPSHOT_NAME)

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)

    @ddt.data(0, 10)
    def test__has_records(self, num_records):
        result = self.client._has_records({'num_records': num_records})

        if not num_records or num_records == 0:
            self.assertFalse(result)
        else:
            self.assertTrue(result)

    def test_vserver_exists(self):
        query = {
            'name': fake.VSERVER_NAME
        }
        return_value = fake.SVMS_LIST_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))

        result = self.client.vserver_exists(fake.VSERVER_NAME)

        self.client.send_request.assert_called_once_with(
            '/svm/svms', 'get', query=query, enable_tunneling=False)
        self.client._has_records.assert_called_once_with(
            fake.SVMS_LIST_SIMPLE_RESPONSE_REST)

        self.assertEqual(result, True)

    def test_get_aggregate(self):

        response = fake.AGGR_GET_ITER_RESPONSE_REST['records']
        self.mock_object(self.client,
                         '_get_aggregates',
                         mock.Mock(return_value=response))

        result = self.client.get_aggregate(fake.SHARE_AGGREGATE_NAME)

        fields = ('name,block_storage.primary.raid_type,'
                  'block_storage.storage_type,snaplock_type')

        self.client._get_aggregates.assert_has_calls([
            mock.call(
                aggregate_names=[fake.SHARE_AGGREGATE_NAME],
                fields=fields)])

        expected = {
            'name': fake.SHARE_AGGREGATE_NAME,
            'raid-type': response[0]['block_storage']['primary']['raid_type'],
            'is-hybrid':
                response[0]['block_storage']['storage_type'] == 'hybrid',
            'snaplock-type': response[0]['snaplock_type'],
            'is-snaplock': response[0]['is_snaplock']
        }

        self.assertEqual(expected, result)

    def test_get_cluster_aggregate_attributes(self):

        response = fake.AGGR_GET_ITER_RESPONSE_REST['records']
        self.mock_object(self.client,
                         '_get_aggregates',
                         mock.Mock(return_value=response))

        result = self.client.get_cluster_aggregate_attributes(
            fake.SHARE_AGGREGATE_NAMES)

        fields = 'name,space,data_encryption.software_encryption_enabled'
        self.client._get_aggregates.assert_has_calls([
            mock.call(
                aggregate_names=fake.SHARE_AGGREGATE_NAMES,
                fields=fields)])

        expected = {
            response[0]['name']: {
                'available': 568692293632,
                'total': 1271819509760,
                'used': 703127216128,
                'encryption_enabled': True,
            },
            response[1]['name']: {
                'available': 727211110400,
                'total': 1426876227584,
                'used': 699665117184,
                'encryption_enabled': False,
            }
        }

        self.assertDictEqual(expected, result)

    def test_list_non_root_aggregates(self):
        return_value = fake.FAKE_AGGR_LIST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.list_non_root_aggregates()

        expected = [fake.SHARE_AGGREGATE_NAMES_LIST[0]]
        self.assertEqual(expected, result)

    def test__get_aggregates(self):

        api_response = fake.AGGR_GET_ITER_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=api_response))
        result = self.client._get_aggregates(
            aggregate_names=fake.SHARE_AGGREGATE_NAMES)
        expected = fake.AGGR_GET_ITER_RESPONSE_REST['records']
        self.assertEqual(expected, result)

    def test_get_node_for_aggregate(self):

        response = fake.AGGR_GET_ITER_RESPONSE_REST['records']
        self.mock_object(self.client,
                         '_get_aggregates',
                         mock.Mock(return_value=response))
        result = self.client.get_node_for_aggregate(fake.SHARE_AGGREGATE_NAME)
        expected = 'fake_home_node_name'
        self.assertEqual(expected, result)

    @ddt.data({'types': {'FCAL'}, 'expected': ['FCAL']},
              {'types': {'SATA', 'SSD'}, 'expected': ['SATA', 'SSD']}, )
    @ddt.unpack
    def test_get_aggregate_disk_types(self, types, expected):

        mock_get_aggregate_disk_types = self.mock_object(
            self.client, '_get_aggregate_disk_types',
            mock.Mock(return_value=types))

        result = self.client.get_aggregate_disk_types(
            fake.SHARE_AGGREGATE_NAME)

        self.assertEqual(sorted(expected), sorted(result))
        mock_get_aggregate_disk_types.assert_called_once_with(
            fake.SHARE_AGGREGATE_NAME)

    def test_volume_exists(self):
        query = {
            'name': fake.VOLUME_NAMES[0]
        }
        return_value = fake.VOLUME_LIST_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))

        result = self.client.volume_exists(fake.VOLUME_NAMES[0])

        self.client.send_request.assert_called_once_with(
            '/storage/volumes', 'get', query=query)
        self.client._has_records.assert_called_once_with(
            fake.VOLUME_LIST_SIMPLE_RESPONSE_REST)
        self.assertEqual(result, True)

    def test_list_vserver_aggregates(self):

        self.mock_object(self.client,
                         'get_vserver_aggregate_capacities',
                         mock.Mock(return_value=fake.VSERVER_AGGREGATES))

        result = self.client.list_vserver_aggregates()

        self.assertListEqual(list(fake.VSERVER_AGGREGATES.keys()), result)

    def test_list_vserver_aggregates_none_found(self):

        self.mock_object(self.client,
                         'get_vserver_aggregate_capacities',
                         mock.Mock(return_value={}))

        result = self.client.list_vserver_aggregates()

        self.assertListEqual([], result)

    def test_get_vserver_aggregate_capacities(self):

        response = fake.FAKE_SVM_AGGREGATES
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=response))

        result = self.client.get_vserver_aggregate_capacities(
            fake.SHARE_AGGREGATE_NAMES_LIST)

        query = {
            'fields': 'name,aggregates.name,aggregates.available_size'
        }

        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get', query=query)])

        expected = {
            response['records'][0].get('aggregates')[0].get('name'): {
                'available': 568692293632,
            },
            response['records'][0].get('aggregates')[1].get('name'): {
                'available': 727211110400,
            }
        }

        self.assertDictEqual(expected, result)

    def test_get_vserver_aggregate_capacities_partial_request(self):
        response = fake.FAKE_SVM_AGGREGATES
        size = response['records'][0].get('aggregates')[0].get(
            'available_size')
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=response))

        result = self.client.get_vserver_aggregate_capacities(
            [fake.SHARE_AGGREGATE_NAMES[0]])

        expected = {
            fake.SHARE_AGGREGATE_NAMES[0]: {
                'available': size
            }
        }
        self.assertDictEqual(expected, result)

    def test_get_vserver_aggregate_capacities_aggregate_not_found(self):
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=fake.FAKE_SVM_AGGR_EMPTY))

        result = self.client.get_vserver_aggregate_capacities(
            ['other-aggr'])

        self.assertDictEqual({}, result)
        self.assertEqual(1, client_cmode_rest.LOG.warning.call_count)

    def test_get_vserver_aggregate_capacities_none_requested(self):
        result = self.client.get_vserver_aggregate_capacities([])
        self.assertEqual({}, result)

    @ddt.data((None, None),
              (fake.QOS_MAX_THROUGHPUT, None),
              (fake.QOS_MAX_THROUGHPUT_IOPS, None),
              (None, None),
              (None, fake.QOS_MIN_THROUGHPUT),
              (None, fake.QOS_MIN_THROUGHPUT_IOPS),
              (fake.QOS_MAX_THROUGHPUT_IOPS, fake.QOS_MIN_THROUGHPUT_IOPS))
    @ddt.unpack
    def test_qos_policy_group_create_legacy(self, max_throughput,
                                            min_throughput):
        return_value = fake.GENERIC_JOB_POST_RESPONSE
        body = {
            'name': fake.QOS_POLICY_GROUP_NAME,
            'svm.name': fake.VSERVER_NAME,
        }
        if max_throughput:
            if 'iops' in max_throughput:
                qos = fake.QOS_MAX_THROUGHPUT_IOPS_NO_UNIT
                body['fixed.max_throughput_iops'] = qos
            else:
                qos = math.ceil(fake.QOS_MAX_THROUGHPUT_NO_UNIT / units.Mi)
                body['fixed.max_throughput_mbps'] = qos

        if min_throughput:
            if 'iops' in min_throughput:
                qos = fake.QOS_MIN_THROUGHPUT_IOPS_NO_UNIT
                body['fixed.min_throughput_iops'] = qos
            else:
                qos = math.ceil(fake.QOS_MIN_THROUGHPUT_NO_UNIT / units.Mi)
                body['fixed.min_throughput_mbps'] = qos

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.qos_policy_group_create_legacy(
            fake.QOS_POLICY_GROUP_NAME, fake.VSERVER_NAME,
            max_throughput, min_throughput)

        self.client.send_request.assert_called_once_with(
            '/storage/qos/policies', 'post', body=body)
        self.assertEqual(result, return_value)

    @ddt.data(None, ['CIFS', 'NFS'])
    def test_get_network_interfaces(self, protocols):
        return_value = fake.GENERIC_NETWORK_INTERFACES_GET_REPONSE

        lif_info = return_value.get('records', [])[0]

        fake_lif = [{
            'uuid': lif_info['uuid'],
            'administrative-status': 'up' if lif_info['enabled'] else 'down',
            'address': lif_info['ip']['address'],
            'home-node': lif_info['location']['home_node']['name'],
            'home-port': lif_info['location']['home_port']['name'],
            'interface-name': lif_info['name'],
            'netmask': lif_info['ip']['netmask'],
            'role': lif_info['services'],
            'vserver': lif_info['svm']['name'],
        }]

        if protocols:
            query = {
                'services': 'data_cifs,data_nfs',
                'fields': 'ip.address,location.home_node.name,'
                          'location.home_port.name,ip.netmask,'
                          'services,svm.name,enabled'
            }
        else:
            query = {
                'fields': 'ip.address,location.home_node.name,'
                          'location.home_port.name,ip.netmask,'
                          'services,svm.name,enabled'
            }

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.get_network_interfaces(protocols)

        self.client.send_request.assert_called_once_with(
            '/network/ip/interfaces', 'get', query=query)

        self.assertEqual(result, fake_lif)

    def test_clear_nfs_export_policy_for_volume(self):

        mock_set_nfs_export_policy_for_volume = self.mock_object(
            self.client, 'set_nfs_export_policy_for_volume')

        self.client.clear_nfs_export_policy_for_volume(fake.SHARE_NAME)

        mock_set_nfs_export_policy_for_volume.assert_called_once_with(
            fake.SHARE_NAME, 'default')

    def test_set_nfs_export_policy_for_volume(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        query = {'name': volume['name']}

        body = {
            'nas.export_policy.name': fake.EXPORT_POLICY_NAME
        }

        self.mock_object(self.client, 'send_request')

        self.client.set_nfs_export_policy_for_volume(
            fake.VOLUME_NAMES[0], fake.EXPORT_POLICY_NAME)

        self.client.send_request.assert_called_once_with(
            '/storage/volumes/', 'patch',
            query=query, body=body)

    def test_set_pcuser_for_volume(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        query = {'name': volume['name']}

        body = {
            'nas.uid': 65534,
        }

        self.mock_object(self.client, 'send_request')

        self.client.set_pcuser_for_volume(fake.VOLUME_NAMES[0])

        self.client.send_request.assert_called_once_with(
            '/storage/volumes', 'patch',
            query=query, body=body)

    def test_create_nfs_export_policy(self):

        body = {'name': fake.EXPORT_POLICY_NAME}

        self.mock_object(self.client, 'send_request')

        self.client.create_nfs_export_policy(fake.EXPORT_POLICY_NAME)

        self.client.send_request.assert_called_once_with(
            '/protocols/nfs/export-policies', 'post', body=body)

    def test_soft_delete_nfs_export_policy(self):
        self.mock_object(self.client, 'delete_nfs_export_policy',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.mock_object(self.client, 'rename_nfs_export_policy')

        self.client.soft_delete_nfs_export_policy(fake.EXPORT_POLICY_NAME)

        self.client.rename_nfs_export_policy.assert_has_calls([
            mock.call(
                fake.EXPORT_POLICY_NAME,
                'deleted_manila_' + fake.EXPORT_POLICY_NAME)])

    def test_rename_nfs_export_policy(self):
        return_uuid = fake.GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES
        uuid = "fake-policy-uuid"

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_uuid))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))

        body = {
            'name': 'fake_new_policy_name'
        }

        self.client.rename_nfs_export_policy(fake.EXPORT_POLICY_NAME,
                                             'fake_new_policy_name')

        self.client._has_records.assert_called_once_with(return_uuid)

        self.client.send_request.assert_has_calls([
            mock.call('/protocols/nfs/export-policies', 'get',
                      query={'name': fake.EXPORT_POLICY_NAME}),
            mock.call(f'/protocols/nfs/export-policies/{uuid}', 'patch',
                      body=body)])

    def test_get_volume_junction_path(self):
        return_value = fake.GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES

        query = {
            'name': fake.SHARE_NAME,
            'fields': 'nas.path'
        }

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.get_volume_junction_path(fake.SHARE_NAME)

        expected = fake.VOLUME_JUNCTION_PATH

        self.client.send_request.assert_called_once_with('/storage/volumes/',
                                                         'get', query=query)

        self.assertEqual(result, expected)

    def test_get_volume_snapshot_attributes(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        expected = {
            'snapdir-access-enabled': 'false',
            'snapshot-policy': 'daily',
        }

        result = self.client.get_volume_snapshot_attributes(fake.SHARE_NAME)
        self.assertEqual(result, expected)

    def test_get_volume(self):
        return_value = fake.GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES

        fake_volume = return_value.get('records', [])[0]

        expected = {
            'aggregate': fake.SHARE_AGGREGATE_NAME,
            'aggr-list': [fake.SHARE_AGGREGATE_NAME],
            'junction-path': fake_volume.get('nas', {}).get('path', ''),
            'name': fake_volume.get('name', ''),
            'owning-vserver-name': fake_volume.get('svm', {}).get('name', ''),
            'type': fake_volume.get('type', ''),
            'style': fake_volume.get('style', ''),
            'size': fake_volume.get('space', {}).get('size', ''),
            'size-used': fake_volume.get('space', {}).get('used', ''),
            'qos-policy-group-name': fake_volume.get('qos', {})
            .get('policy', {})
            .get('name'),
            'style-extended': fake_volume.get('style', ''),
            'snaplock-type': fake_volume.get('snaplock', {}).get('type', '')
        }

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))

        result = self.client.get_volume(fake.SHARE_NAME)

        self.client._has_records.assert_called_once_with(return_value)
        self.assertEqual(result, expected)

    def test_cifs_share_exists(self):
        return_value = fake.VOLUME_LIST_SIMPLE_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))

        result = self.client.cifs_share_exists(fake.SHARE_NAME)

        query = {
            'name': fake.SHARE_NAME,
            'path': fake.VOLUME_JUNCTION_PATH
        }
        self.client._has_records.assert_called_once_with(return_value)
        self.client.send_request.assert_called_once_with(
            '/protocols/cifs/shares', 'get', query=query)
        self.assertTrue(result)

    def test_create_cifs_share(self):

        body = {
            'name': fake.SHARE_NAME,
            'path': fake.VOLUME_JUNCTION_PATH,
            'svm.name': self.client.vserver,
        }

        self.mock_object(self.client, 'send_request')

        self.client.create_cifs_share(fake.SHARE_NAME, f'/{fake.SHARE_NAME}')

        self.client.send_request.assert_called_once_with(
            '/protocols/cifs/shares', 'post', body=body)

    @ddt.data(None, 'fake_security_style')
    def test_set_volume_security_style(self, security_style):

        self.mock_object(self.client, 'send_request')

        if security_style:
            self.client.set_volume_security_style(fake.VOLUME_NAMES[0],
                                                  security_style)
        else:
            self.client.set_volume_security_style(fake.VOLUME_NAMES[0])

        query = {
            'name': fake.VOLUME_NAMES[0],
        }
        body = {
            'nas.security_style': security_style if security_style else 'unix'
        }
        self.client.send_request.assert_called_once_with(
            '/storage/volumes', 'patch', body=body, query=query)

    def test_remove_cifs_share_access(self):
        return_uuid = fake.GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_uuid))

        self.client.remove_cifs_share_access(fake.SHARE_NAME, fake.USER_NAME)

        fake_uuid = "fake_uuid"
        self.client.send_request.assert_has_calls([
            mock.call('/protocols/cifs/shares', 'get',
                      query={'name': fake.SHARE_NAME, 'fields': 'svm.uuid'}),
            mock.call(f'/protocols/cifs/shares/{fake_uuid}/{fake.SHARE_NAME}/'
                      f'acls/{fake.USER_NAME}/windows', 'delete')])

    def test_create_volume(self):

        mock_create_volume_async = self.mock_object(self.client,
                                                    'create_volume_async')
        mock_update = self.mock_object(
            self.client, 'update_volume_efficiency_attributes')
        mock_max_files = self.mock_object(self.client, 'set_volume_max_files')
        options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}
        self.client.create_volume(fake.SHARE_AGGREGATE_NAME,
                                  fake.VOLUME_NAMES[0], fake.SHARE_SIZE,
                                  max_files=1, snaplock_type="enterprise",
                                  **options)
        mock_create_volume_async.assert_called_once_with(
            [fake.SHARE_AGGREGATE_NAME], fake.VOLUME_NAMES[0], fake.SHARE_SIZE,
            is_flexgroup=False, thin_provisioned=False, snapshot_policy=None,
            language=None, max_files=1, snapshot_reserve=None,
            volume_type='rw', qos_policy_group=None, encrypt=False,
            adaptive_qos_policy_group=None, mount_point_name=None,
            efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME,
            snaplock_type="enterprise", aggregate_encrypted=None,
        )
        mock_update.assert_called_once_with(
            fake.VOLUME_NAMES[0], False, False,
            efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME)
        mock_max_files.assert_called_once_with(fake.VOLUME_NAMES[0], 1)

    def test_create_volume_async(self):
        body = {
            'size': 1073741824,
            'name': fake.VOLUME_NAMES[0],
            'style': 'flexvol',
            'aggregates': [{'name': fake.SHARE_AGGREGATE_NAME}]
        }

        return_value = fake.GENERIC_JOB_POST_RESPONSE

        expected_result = {
            'jobid': fake.GENERIC_JOB_POST_RESPONSE['job']['uuid'],
            'error-code': '',
            'error-message': '',
        }

        self.mock_object(self.client, '_get_create_volume_body',
                         mock.Mock(return_value={}))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.create_volume_async([
            fake.SHARE_AGGREGATE_NAME], fake.VOLUME_NAMES[0], 1,
            is_flexgroup=False)

        self.client._get_create_volume_body.assert_called_once_with(
            fake.VOLUME_NAMES[0], False, None, None, None, 'rw', None, False,
            None, None, None, None)
        self.client.send_request.assert_called_once_with(
            '/storage/volumes', 'post', body=body, wait_on_accepted=True)
        self.assertEqual(expected_result, result)

    def test_get_volume_efficiency_status(self):
        return_value = fake.VOLUME_LIST_SIMPLE_RESPONSE_REST

        query = {
            'efficiency.volume_path': '/vol/%s' % fake.VOLUME_NAMES[0],
            'fields': 'efficiency.state,efficiency.compression'
        }

        expected_result = {
            'dedupe': True,
            'compression': True
        }

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.get_volume_efficiency_status(fake.VOLUME_NAMES[0])

        self.client.send_request.assert_called_once_with(
            '/storage/volumes', 'get', query=query)
        self.assertEqual(expected_result, result)

    def test_enable_dedupe_async(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        body = {
            'efficiency': {'dedupe': 'background'}
        }

        self.client.enable_dedupe_async(fake.VOLUME_NAMES[0])

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)
        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])

    def test_disable_dedupe_async(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        body = {
            'efficiency': {'dedupe': 'none'}
        }

        self.client.disable_dedupe_async(fake.VOLUME_NAMES[0])

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)
        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])

    def test_enable_compression_async(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        body = {
            'efficiency': {'compression': 'background'}
        }

        self.client.enable_compression_async(fake.VOLUME_NAMES[0])

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)
        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])

    def test_disable_compression_async(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        body = {
            'efficiency': {'compression': 'none'}
        }

        self.client.disable_compression_async(fake.VOLUME_NAMES[0])

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)
        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])

    def test_apply_volume_efficiency_policy(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        body = {
            'efficiency': {'policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}
        }

        self.client.apply_volume_efficiency_policy(
            fake.VOLUME_NAMES[0],
            efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME
        )

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)
        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])

    def test_apply_volume_efficiency_none_policy(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        self.client.apply_volume_efficiency_policy(
            fake.VOLUME_NAMES[0],
            efficiency_policy=None
        )

        self.client._get_volume_by_args.assert_not_called()

    def test_set_volume_max_files(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        fake_max_files = '40000'

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        body = {
            'files.maximum': int(fake_max_files)
        }

        self.client.set_volume_max_files(fake.VOLUME_NAMES[0], fake_max_files)

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)
        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])

    def test_set_volume_max_files_retry_allocated(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        fake_max_files = '40000'
        fake_used_files = '30000'
        alloc_files = {'maximum': fake_max_files, 'used': fake_used_files}
        side_effect = [
            netapp_api.api.NaApiError(
                code=netapp_api.EREST_CANNOT_MODITY_SPECIFIED_FIELD), None]

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(side_effect=side_effect))
        self.mock_object(self.client, 'get_volume_allocated_files',
                         mock.Mock(return_value=alloc_files))

        body_before = {
            'files.maximum': int(fake_max_files)
        }
        body_retry = {
            'files.maximum': int(fake_used_files)
        }

        self.client.set_volume_max_files(
            fake.VOLUME_NAMES[0], fake_max_files, retry_allocated=True)

        mock_sr.assert_has_calls([
            mock.call(f'/storage/volumes/{uuid}', 'patch', body=body_before),
            mock.call(f'/storage/volumes/{uuid}', 'patch', body=body_retry),
        ])
        self.client._get_volume_by_args.assert_called()

    def test_set_volume_snapdir_access(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        fake_hide_snapdir = 'fake-snapdir'

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        body = {
            'snapshot_directory_access_enabled': str(
                not fake_hide_snapdir).lower()
        }

        self.client.set_volume_snapdir_access(fake.VOLUME_NAMES[0],
                                              fake_hide_snapdir)

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)
        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])

    def test_get_fpolicy_scopes(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.GENERIC_FPOLICY_RESPONSE

        query = {
            'name': fake.FPOLICY_POLICY_NAME,
            'scope.include_shares': fake.VOLUME_NAMES[0],
            'scope.include_extension': fake.FPOLICY_EXT_TO_INCLUDE,
            'scope.exclude_extension': fake.FPOLICY_EXT_TO_EXCLUDE
        }

        expected_result = [
            {
                'policy-name': fake.FPOLICY_POLICY_NAME,
                'file-extensions-to-include': fake.FPOLICY_EXT_TO_INCLUDE_LIST,
                'file-extensions-to-exclude': fake.FPOLICY_EXT_TO_EXCLUDE_LIST,
                'shares-to-include': [fake.VOLUME_NAMES[0]],
            }
        ]

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.get_fpolicy_scopes(
            fake.VOLUME_NAMES[0], fake.FPOLICY_POLICY_NAME,
            fake.FPOLICY_EXT_TO_INCLUDE_LIST, fake.FPOLICY_EXT_TO_EXCLUDE_LIST,
            [fake.VOLUME_NAMES[0]])

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/protocols/fpolicy/{uuid}/policies', 'get', query=query)

        self.assertEqual(expected_result, result)

    def test_get_fpolicy_policies_status(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.GENERIC_FPOLICY_RESPONSE

        query = {
            'name': fake.FPOLICY_POLICY_NAME,
            'enabled': 'true'
        }

        expected_result = [
            {
                'policy-name': fake.FPOLICY_POLICY_NAME,
                'status': True,
                'sequence-number': 1
            }
        ]

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.get_fpolicy_policies_status(
            fake.VOLUME_NAMES[0], fake.FPOLICY_POLICY_NAME, 'true')

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/protocols/fpolicy/{uuid}/policies', 'get', query=query)

        self.assertEqual(expected_result, result)

    def test_get_fpolicy_policies(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.GENERIC_FPOLICY_RESPONSE

        query = {
            'name': fake.FPOLICY_POLICY_NAME,
            'engine.name': 'native',
            'events': fake.FPOLICY_EVENT_NAME
        }

        expected_result = [
            {
                'policy-name': fake.FPOLICY_POLICY_NAME,
                'engine-name': 'native',
                'events': [fake.FPOLICY_EVENT_NAME]
            }
        ]

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.get_fpolicy_policies(
            fake.VOLUME_NAMES[0], fake.FPOLICY_POLICY_NAME, 'native',
            [fake.FPOLICY_EVENT_NAME])

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/protocols/fpolicy/{uuid}/policies', 'get', query=query)

        self.assertEqual(expected_result, result)

    def test_get_fpolicy_events(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]
        return_value = fake.GENERIC_FPOLICY_EVENTS_RESPONSE

        query = {
            'name': fake.FPOLICY_EVENT_NAME,
            'protocol': fake.FPOLICY_PROTOCOL,
            'fields': 'file_operations.create,file_operations.write,'
                      'file_operations.rename'
        }

        expected_result = [
            {
                'event-name': fake.FPOLICY_EVENT_NAME,
                'protocol': fake.FPOLICY_PROTOCOL,
                'file-operations': fake.FPOLICY_FILE_OPERATIONS_LIST
            }
        ]

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.get_fpolicy_events(
            fake.VOLUME_NAMES[0], fake.FPOLICY_EVENT_NAME,
            fake.FPOLICY_PROTOCOL, fake.FPOLICY_FILE_OPERATIONS_LIST)

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/protocols/fpolicy/{uuid}/events', 'get', query=query)

        self.assertEqual(expected_result, result)

    def test_create_fpolicy_event(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]

        body = {
            'name': fake.FPOLICY_EVENT_NAME,
            'protocol': fake.FPOLICY_PROTOCOL,
            'file_operations.create': 'true',
            'file_operations.write': 'true',
            'file_operations.rename': 'true'
        }

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.client.create_fpolicy_event(
            fake.VOLUME_NAMES[0], fake.FPOLICY_EVENT_NAME,
            fake.FPOLICY_PROTOCOL, fake.FPOLICY_FILE_OPERATIONS_LIST)

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/protocols/fpolicy/{uuid}/events', 'post', body=body)

    def test_delete_fpolicy_policy(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.client.delete_fpolicy_policy(
            fake.VOLUME_NAMES[0], fake.FPOLICY_POLICY_NAME)

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/protocols/fpolicy/{uuid}/policies/{fake.FPOLICY_POLICY_NAME}',
            'delete')

    def test_delete_fpolicy_event(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.client.delete_fpolicy_event(
            fake.VOLUME_NAMES[0], fake.FPOLICY_EVENT_NAME)

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/protocols/fpolicy/{uuid}/events/{fake.FPOLICY_EVENT_NAME}',
            'delete')

    def test_enable_fpolicy_policy(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]

        body = {
            'priority': 1,
        }

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.client.enable_fpolicy_policy(
            fake.VOLUME_NAMES[0], fake.FPOLICY_POLICY_NAME, 1)

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/protocols/fpolicy/{uuid}/policies/{fake.FPOLICY_POLICY_NAME}',
            'patch', body=body)

    def test_create_fpolicy_policy_with_scope(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        uuid = volume["uuid"]

        body = {
            'name': fake.FPOLICY_POLICY_NAME,
            'events.name': fake.FPOLICY_EVENT_NAME,
            'engine.name': fake.FPOLICY_ENGINE,
            'scope.include_shares': [fake.VOLUME_NAMES[0]],
            'scope.include_extension': fake.FPOLICY_EXT_TO_INCLUDE_LIST,
            'scope.exclude_extension': fake.FPOLICY_EXT_TO_EXCLUDE_LIST
        }

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.client.create_fpolicy_policy_with_scope(
            fake.FPOLICY_POLICY_NAME, fake.VOLUME_NAMES[0],
            fake.FPOLICY_EVENT_NAME, fake.FPOLICY_ENGINE,
            extensions_to_include=fake.FPOLICY_EXT_TO_INCLUDE,
            extensions_to_exclude=fake.FPOLICY_EXT_TO_EXCLUDE)

        self.client._get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        self.client.send_request.assert_called_once_with(
            f'/protocols/fpolicy/{uuid}/policies', 'post', body=body)

    def test_delete_nfs_export_policy(self):
        policy_name = 'fake_policy_name'

        query = {
            'name': policy_name,
        }

        api_response = fake.EXPORT_POLICY_REST

        mock_sr = self.mock_object(self.client, 'send_request', mock.Mock(
            return_value=api_response))

        if not api_response.get('records'):
            return
        id = api_response.get('records')[0]['id']

        self.client.delete_nfs_export_policy(policy_name)

        mock_sr.assert_has_calls([
            mock.call('/protocols/nfs/export-policies', 'get',
                      query=query),
            mock.call(f'/protocols/nfs/export-policies/{id}', 'delete'),
        ])

    def test_delete_volume(self):
        """Deletes a volume."""
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))

        mock_sr = self.mock_object(self.client, 'send_request')
        # Get volume UUID.
        uuid = volume['uuid']

        self.client.delete_volume('fake_volume_name')

        mock_sr.assert_called_once_with(f'/storage/volumes/{uuid}', 'delete')

    def test_soft_delete_volume_error(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(
            self.client, 'send_request',
            self._mock_api_error(
                code=netapp_api.EREST_VOLDEL_NOT_ALLOW_BY_CLONE))
        mock_rename = self.mock_object(self.client, 'rename_volume')

        # Get volume UUID.
        uuid = volume['uuid']

        self.client.soft_delete_volume('fake_volume_name')

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'delete')
        mock_rename.assert_called_once_with(
            'fake_volume_name',
            client_cmode_rest.DELETED_PREFIX + 'fake_volume_name')

    def test_soft_delete_volume_error_return_errors(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(
            self.client, 'send_request',
            self._mock_api_error(
                code=netapp_api.EREST_VOLDEL_NOT_ALLOW_BY_CLONE))

        ret = self.client.soft_delete_volume('fake_volume_name',
                                             return_errors=True)
        self.assertEqual('del_not_allow_by_clone', ret)

    def test_prune_deleted_volumes_no_clones_online(self):
        api_response = [fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST]
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        self.mock_object(self.client, 'get_deleted_volumes_to_prune',
                         mock.Mock(return_value=api_response))
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.mock_object(
            copy, 'deepcopy', mock.Mock(return_value=self.client))
        mock_get_clones = self.mock_object(
            self.client, 'get_clones_of_parent_volume',
            mock.Mock(return_value=[]))

        self.client.prune_deleted_volumes()

        mock_get_clones.assert_called_once_with(
            api_response[0]['svm']['name'], api_response[0]['name'])

    def test_prune_deleted_volumes_no_clones_offline(self):
        response = [fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST]
        api_response = copy.deepcopy(response)
        api_response[0]['state'] = 'offline'

        self.mock_object(self.client, 'get_deleted_volumes_to_prune',
                         mock.Mock(return_value=api_response))
        self.mock_object(
            copy, 'deepcopy', mock.Mock(return_value=self.client))
        mock_get_clones = self.mock_object(
            self.client, 'get_clones_of_parent_volume',
            mock.Mock(return_value=[]))
        mock_delete = self.mock_object(
            self.client, 'delete_volume',
            mock.Mock(return_value='success'))

        self.client.prune_deleted_volumes()

        mock_get_clones.assert_called_once_with(
            api_response[0]['svm']['name'], api_response[0]['name'])
        mock_delete.assert_called()

    def test_prune_deleted_volumes_clones_online(self):
        api_response = [fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST]
        self.mock_object(self.client, 'get_deleted_volumes_to_prune',
                         mock.Mock(return_value=api_response))
        self.mock_object(
            copy, 'deepcopy', mock.Mock(return_value=self.client))
        mock_get_clones = self.mock_object(
            self.client, 'get_clones_of_parent_volume',
            mock.Mock(return_value=['fake_clone']))
        mock_status = self.mock_object(
            self.client, 'volume_clone_split_status',
            mock.Mock(return_value='unknown'))
        mock_start = self.mock_object(
            self.client, 'volume_clone_split_start')

        self.client.prune_deleted_volumes()

        mock_get_clones.assert_called_once_with(
            api_response[0]['svm']['name'], api_response[0]['name'])
        mock_status.assert_called_once_with('fake_clone')
        mock_start.assert_called_once_with('fake_clone')

    def test_prune_deleted_volumes_clones_offline(self):
        response = [fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST]
        api_response = copy.deepcopy(response)
        api_response[0]['state'] = 'offline'

        self.mock_object(self.client, 'get_deleted_volumes_to_prune',
                         mock.Mock(return_value=api_response))
        self.mock_object(
            copy, 'deepcopy', mock.Mock(return_value=self.client))
        mock_get_clones = self.mock_object(
            self.client, 'get_clones_of_parent_volume',
            mock.Mock(return_value=['fake_clone']))
        mock_online = self.mock_object(self.client, 'online_volume')

        self.client.prune_deleted_volumes()

        mock_get_clones.assert_called_once_with(
            api_response[0]['svm']['name'], api_response[0]['name'])
        mock_online.assert_has_calls([
            mock.call(api_response[0]['name']),
            mock.call('fake_clone'),
        ])

    def test__unmount_volume(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        mock_send_request = self.mock_object(self.client, 'send_request')
        uuid = volume['uuid']

        # Unmount volume async operation.
        body = {"nas": {"path": ""}}

        self.client._unmount_volume('fake_volume_name')
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)

    def test_online_volume(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        mock_send_request = self.mock_object(self.client, 'send_request')
        uuid = volume['uuid']

        body = {'state': 'online'}
        self.client.online_volume('fake_volume_name')
        mock_send_request.assert_called_once_with(f'/storage/volumes/{uuid}',
                                                  'patch', body=body)

    def test_offline_volume(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        mock_send_request = self.mock_object(self.client, 'send_request')
        uuid = volume['uuid']

        body = {'state': 'offline'}
        self.client.offline_volume('fake_volume_name')
        mock_send_request.assert_called_once_with(f'/storage/volumes/{uuid}',
                                                  'patch', body=body)

    def test_adaptive_qos_policy_group_create(self):
        return_value = fake.GENERIC_JOB_POST_RESPONSE
        body = {
            'name': fake.ADAPTIVE_QOS_POLICY_GROUP_NAME,
            'svm.name': fake.VSERVER_NAME,
        }

        qos_type_specs = {
            'peak_iops': 100,
            'expected_iops': 50,
            'absolute_min_iops': 20,
            'block_size': 'any',
        }

        body['adaptive.peak_iops'] = 100
        body['adaptive.expected_iops'] = 50
        body['adaptive.absolute_min_iops'] = 20
        body['adaptive.block_size'] = 'any'

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.adaptive_qos_policy_group_create(
            fake.ADAPTIVE_QOS_POLICY_GROUP_NAME, fake.VSERVER_NAME,
            qos_type_specs)

        self.client.send_request.assert_called_once_with(
            '/storage/qos/policies', 'post', body=body)
        self.assertEqual(result, return_value)

    def test_adaptive_qos_policy_group_get(self):
        adaptive_qos_policy_group_name = 'extreme'
        qos_policy_group = fake.QOS_POLICY_GROUP_REST
        qos_policy = qos_policy_group.get('records')[0]
        absolute_min_iops = qos_policy.get(
            'adaptive', {}).get('absolute_min_iops')
        block_size = qos_policy.get(
            'adaptive', {}).get('block_size')
        peak_iops = qos_policy.get(
            'adaptive', {}).get('peak_iops')
        peak_iops_allocation = qos_policy.get(
            'adaptive', {}).get('peak_iops_allocation')
        expected_iops = qos_policy.get(
            'adaptive', {}).get('expected_iops')
        expected_iops_allocation = qos_policy.get(
            'adaptive', {}).get('expected_iops_allocation')

        expected = {
            'policy-group': qos_policy.get('name'),
            'vserver': qos_policy.get('svm', {}).get('name'),
            'absolute_min_iops': (
                absolute_min_iops if absolute_min_iops else 0),
            'block_size': block_size if block_size else None,
            'peak_iops': peak_iops if peak_iops else 0,
            'peak_iops_allocation': (
                peak_iops_allocation if peak_iops_allocation else None),
            'expected_iops_allocation': (
                expected_iops_allocation if
                expected_iops_allocation else None),
            'expected_iops': expected_iops if expected_iops else 0,
            'num-workloads': int(qos_policy.get('object_count')),
        }

        query = {
            'name': adaptive_qos_policy_group_name,
            'fields': 'name,object_count,adaptive.absolute_min_iops,'
                      'adaptive.block_size,svm.name,'
                      'adaptive.expected_iops,adaptive.peak_iops,'
                      'adaptive.expected_iops_allocation,'
                      'adaptive.peak_iops_allocation',
        }

        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=qos_policy_group))

        result = self.client.adaptive_qos_policy_group_get(
            adaptive_qos_policy_group_name)
        mock_sr.assert_called_once_with('/storage/qos/policies', 'get',
                                        query=query)
        self.assertEqual(expected, result)

    def test_adaptive_qos_policy_group_modify(self):
        return_request = {
            'records': [{'uuid': 'fake_uuid'}]
        }
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=return_request))
        self.client.adaptive_qos_policy_group_modify(
            'qos_fake_name', {'expected_iops': 100})

        query = {
            'name': 'qos_fake_name',
        }
        body = {
            'adaptive.expected_iops': 100,
        }
        mock_sr.assert_has_calls([
            mock.call('/storage/qos/policies', 'get', query=query),
            mock.call('/storage/qos/policies/fake_uuid', 'patch', body=body),
        ])

    def test_adaptive_qos_policy_group_modify_error(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(exception.NetAppException,
                          self.client.adaptive_qos_policy_group_modify,
                          fake.ADAPTIVE_QOS_POLICY_GROUP_NAME,
                          {})

    def test_qos_policy_group_rename(self):
        """Renames a QoS policy group."""

        qos_policy_group_name = 'extreme'
        new_name = 'new_name'
        res = fake.QOS_POLICY_GROUP_REST
        mock_send_request = self.mock_object(self.client, 'send_request',
                                             mock.Mock(return_value=res))
        query = {
            'name': qos_policy_group_name,
            'fields': 'uuid',
        }
        uuid = res.get('records')[0]['uuid']
        body = {"name": new_name}

        self.client.qos_policy_group_rename(qos_policy_group_name, new_name)

        mock_send_request.assert_has_calls([
            mock.call('/storage/qos/policies', 'get', query=query),
            mock.call(f'/storage/qos/policies/{uuid}', 'patch',
                      body=body),
        ])

    def test_qos_policy_group_get_legacy(self):
        qos_policy_group_name = 'extreme'
        qos_policy_group = fake.QOS_POLICY_GROUP_REST
        qos_policy = qos_policy_group.get('records')[0]
        max_throughput = qos_policy.get('fixed',
                                        {}).get('max_throughput_iops')
        min_throughput = qos_policy.get('fixed',
                                        {}).get('min_throughput_iops')

        expected = {
            'policy-group': qos_policy.get('name'),
            'vserver': qos_policy.get('svm', {}).get('name'),
            'max-throughput': max_throughput if max_throughput else None,
            'min-throughput': min_throughput if min_throughput else None,
            'num-workloads': int(qos_policy.get('object_count')),
        }

        query = {
            'name': qos_policy_group_name,
            'fields': 'name,object_count,fixed.max_throughput_iops,' +
                      'fixed.max_throughput_mbps,svm.name,' +
                      'fixed.min_throughput_iops,fixed.min_throughput_mbps',
        }

        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=qos_policy_group))

        result = self.client.qos_policy_group_get_legacy(qos_policy_group_name)
        mock_sr.assert_called_once_with('/storage/qos/policies', 'get',
                                        query=query)
        self.assertEqual(expected, result)

    def test_qos_policy_group_create(self):
        return_value = fake.GENERIC_JOB_POST_RESPONSE
        body = {
            'name': fake.QOS_POLICY_GROUP_NAME,
            'svm.name': fake.VSERVER_NAME,
        }
        qos_type_specs = {
            'max_throughput_mbps': '10',
            'max_throughput_iops': '20',
            'min_throughput_mbps': '30',
            'min_throughput_iops': '40',
        }

        body['fixed.max_throughput_mbps'] = 10
        body['fixed.max_throughput_iops'] = 20
        body['fixed.min_throughput_mbps'] = 30
        body['fixed.min_throughput_iops'] = 40
        body['fixed.capacity_shared'] = 'false'

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.qos_policy_group_create(
            fake.QOS_POLICY_GROUP_NAME, fake.VSERVER_NAME, qos_type_specs)

        self.client.send_request.assert_called_once_with(
            '/storage/qos/policies', 'post', body=body)
        self.assertEqual(result, return_value)

    def test_remove_unused_qos_policy_groups(self):

        result = fake.QOS_POLICY_GROUP_REST

        query = {
            'name': '%s*' % client_cmode_rest.DELETED_PREFIX,
            'fields': 'uuid,name',
        }

        mock_send_request = self.mock_object(self.client, 'send_request',
                                             mock.Mock(return_value=result))

        res = result.get('records')
        for record in res:
            uuid = record['uuid']

        self.client.remove_unused_qos_policy_groups()

        mock_send_request.assert_has_calls([
            mock.call('/storage/qos/policies', 'get', query=query),
            mock.call(f'/storage/qos/policies/{uuid}', 'delete')])

    def test_unmount_volume(self):

        self.mock_object(self.client, '_unmount_volume')

        self.client.unmount_volume(fake.SHARE_NAME)

        self.client._unmount_volume.assert_called_once_with(fake.SHARE_NAME)
        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)
        self.assertEqual(0, client_cmode_rest.LOG.warning.call_count)

    def test_unmount_volume_api_error(self):

        self.mock_object(self.client,
                         '_unmount_volume',
                         self._mock_api_error())

        self.assertRaises(netapp_api.api.NaApiError,
                          self.client.unmount_volume,
                          fake.SHARE_NAME)

        self.assertEqual(1, self.client._unmount_volume.call_count)
        self.assertEqual(0, client_cmode_rest.LOG.debug.call_count)
        self.assertEqual(0, client_cmode_rest.LOG.warning.call_count)

    def test_unmount_volume_with_retries(self):
        return_code = netapp_api.EREST_UNMOUNT_FAILED_LOCK
        side_effect = [netapp_api.api.NaApiError(code=return_code,
                                                 message='...job ID...')] * 5
        side_effect.append(None)
        self.mock_object(self.client,
                         '_unmount_volume',
                         mock.Mock(side_effect=side_effect))
        self.mock_object(time, 'sleep')

        self.client.unmount_volume(fake.SHARE_NAME)

        self.assertEqual(6, self.client._unmount_volume.call_count)
        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)
        self.assertEqual(5, client_cmode_rest.LOG.warning.call_count)

    def test_unmount_volume_with_max_retries(self):
        return_code = netapp_api.EREST_UNMOUNT_FAILED_LOCK
        side_effect = [netapp_api.api.NaApiError(code=return_code,
                                                 message='...job ID...')] * 30
        self.mock_object(self.client,
                         '_unmount_volume',
                         mock.Mock(side_effect=side_effect))
        self.mock_object(time, 'sleep')

        self.assertRaises(exception.NetAppException,
                          self.client.unmount_volume,
                          fake.SHARE_NAME)

        self.assertEqual(10, self.client._unmount_volume.call_count)
        self.assertEqual(0, client_cmode_rest.LOG.debug.call_count)
        self.assertEqual(10, client_cmode_rest.LOG.warning.call_count)

    def test_qos_policy_group_exists(self):
        mock = self.mock_object(self.client, 'qos_policy_group_get_legacy')
        response = self.client.qos_policy_group_exists('extreme')
        mock.assert_called_once_with('extreme')
        self.assertTrue(response)

    def test_mark_qos_policy_group_for_deletion_rename_failure(self):
        self.mock_object(self.client, 'qos_policy_group_exists',
                         mock.Mock(return_value=True))
        self.mock_object(self.client, 'qos_policy_group_rename',
                         mock.Mock(side_effect=netapp_api.api.NaApiError))
        self.mock_object(client_cmode_rest.LOG, 'warning')
        self.mock_object(self.client, 'remove_unused_qos_policy_groups')

        retval = self.client.mark_qos_policy_group_for_deletion(
            fake.QOS_POLICY_GROUP_NAME)

        self.assertIsNone(retval)
        client_cmode_rest.LOG.warning.assert_called_once()
        self.client.qos_policy_group_exists.assert_called_once_with(
            fake.QOS_POLICY_GROUP_NAME)
        self.client.qos_policy_group_rename.assert_called_once_with(
            fake.QOS_POLICY_GROUP_NAME,
            client_cmode_rest.DELETED_PREFIX + fake.QOS_POLICY_GROUP_NAME)
        self.client.remove_unused_qos_policy_groups.assert_called_once_with()

    @ddt.data(True, False)
    def test_mark_qos_policy_group_for_deletion_policy_exists(self, exists):
        self.mock_object(self.client, 'qos_policy_group_exists',
                         mock.Mock(return_value=exists))
        self.mock_object(self.client, 'qos_policy_group_rename')
        mock_remove_unused_policies = self.mock_object(
            self.client, 'remove_unused_qos_policy_groups')
        self.mock_object(client_cmode_rest.LOG, 'warning')

        retval = self.client.mark_qos_policy_group_for_deletion(
            fake.QOS_POLICY_GROUP_NAME)

        self.assertIsNone(retval)

        if exists:
            self.client.qos_policy_group_rename.assert_called_once_with(
                fake.QOS_POLICY_GROUP_NAME,
                client_cmode_rest.DELETED_PREFIX + fake.QOS_POLICY_GROUP_NAME)
            mock_remove_unused_policies.assert_called_once_with()
        else:
            self.assertFalse(self.client.qos_policy_group_rename.called)
            self.assertFalse(
                self.client.remove_unused_qos_policy_groups.called)
        self.assertFalse(client_cmode_rest.LOG.warning.called)

    def test_set_volume_size(self):
        unique_volume_return = {'uuid': 'fake_uuid'}
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=unique_volume_return))
        mock_sr = self.mock_object(self.client, 'send_request')
        self.client.set_volume_size('fake_name', 1)

        body = {
            'space.size': 1 * units.Gi
        }
        mock_sr.assert_called_once_with(
            '/storage/volumes/fake_uuid', 'patch', body=body)

    def test_qos_policy_group_modify_legacy(self):
        return_request = {
            'records': [{'uuid': 'fake_uuid'}]
        }
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=return_request))
        self.client.qos_policy_group_modify_legacy(
            'qos_fake_name', '1000iops', '500iops')

        query = {
            'name': 'qos_fake_name',
        }
        body = {
            'fixed.max_throughput_iops': 1000,
            'fixed.max_throughput_mbps': 0,
            'fixed.min_throughput_iops': 500,
            'fixed.min_throughput_mbps': 0,
        }
        mock_sr.assert_has_calls([
            mock.call('/storage/qos/policies', 'get', query=query),
            mock.call('/storage/qos/policies/fake_uuid', 'patch', body=body),
        ])

    @ddt.data(True, False)
    def test_set_volume_filesys_size_fixed(self, filesys_size_fixed):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        mock_send_request = self.mock_object(self.client, 'send_request')
        fake_uuid = volume['uuid']

        self.client.set_volume_filesys_size_fixed(fake.SHARE_NAME,
                                                  filesys_size_fixed)
        body = {
            'space.filesystem_size_fixed': filesys_size_fixed}
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{fake_uuid}',
            'patch', body=body)

    def test_create_snapshot(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        mock_get_volume = self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value=volume))
        mock_send_request = self.mock_object(self.client, 'send_request')

        self.client.create_snapshot(fake.VOLUME_NAMES[0], fake.SNAPSHOT_NAME)

        mock_get_volume.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        body = {
            'name': fake.SNAPSHOT_NAME,
        }
        uuid = volume['uuid']
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}/snapshots', 'post', body=body)

    def test_is_flexgroup_supported(self):
        flexgroup_supported = self.client.is_flexgroup_supported()

        self.assertTrue(flexgroup_supported)

    def test_reset_volume_autosize(self):
        """Test reset_volume_autosize method."""
        mock_sr = self.mock_object(self.client, 'send_request')

        volume_name = fake.VOLUME_NAMES[0]
        vserver_name = fake.VSERVER_NAME

        self.client.reset_volume_autosize(volume_name, vserver_name)

        expected_query = {
            "vserver": vserver_name,
            "volume": volume_name
        }
        expected_body = {
            "autosize-reset": "true"
        }

        mock_sr.assert_called_once_with(
            '/private/cli/volume', 'patch',
            query=expected_query, body=expected_body)

    def test_reset_volume_autosize_api_error(self):
        """Test reset_volume_autosize method handles API errors."""
        mock_sr = self.mock_object(
            self.client, 'send_request',
            mock.Mock(side_effect=netapp_api.api.NaApiError(
                code='fake_code', message='fake_message')))

        volume_name = fake.VOLUME_NAMES[0]
        vserver_name = fake.VSERVER_NAME

        self.assertRaises(
            netapp_api.api.NaApiError,
            self.client.reset_volume_autosize,
            volume_name, vserver_name)

        self.assertTrue(mock_sr.called)

    @ddt.data(True, False)
    def test_is_flexgroup_volume(self, is_flexgroup):
        response = copy.deepcopy(fake.VOLUME_LIST_SIMPLE_RESPONSE_REST)
        expected_style = 'flexgroup' if is_flexgroup else 'flexvol'
        response['records'][0]['style'] = expected_style
        mock_send_request = self.mock_object(self.client, 'send_request',
                                             mock.Mock(return_value=response))
        mock_has_records = self.mock_object(
            self.client, '_has_records', mock.Mock(return_value=True))
        mock_na_utils_is_flexgroup = self.mock_object(
            netapp_utils, 'is_style_extended_flexgroup',
            mock.Mock(return_value=is_flexgroup))

        result = self.client.is_flexgroup_volume(fake.VOLUME_NAMES[0])

        self.assertEqual(is_flexgroup, result)
        query = {
            'name': fake.VOLUME_NAMES[0],
            'fields': 'style'
        }
        mock_send_request.assert_called_once_with('/storage/volumes/', 'get',
                                                  query=query)
        mock_has_records.assert_called_once_with(response)
        mock_na_utils_is_flexgroup.assert_called_once_with(expected_style)

    def test_is_flexgroup_volume_raise_no_records(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake.NO_RECORDS_RESPONSE_REST))
        self.mock_object(
            self.client, '_has_records', mock.Mock(return_value=False))

        self.assertRaises(
            exception.StorageResourceNotFound,
            self.client.is_flexgroup_volume,
            fake.VOLUME_NAMES[0])

    def test_is_flexgroup_volume_raise_more_than_one_volume(self):
        self.mock_object(
            self.client, 'send_request',
            mock.Mock(return_value=fake.VOLUME_GET_ITER_RESPONSE_REST_PAGE))
        self.mock_object(
            self.client, '_has_records', mock.Mock(return_value=True))

        self.assertRaises(
            exception.NetAppException,
            self.client.is_flexgroup_volume,
            fake.VOLUME_NAMES[0])

    @ddt.data(
        {'is_busy': True, 'owners': ['volume_clone']},
        {'is_busy': False, 'owners': ['snap_restore_dependent']})
    @ddt.unpack
    def test__is_busy_snapshot(self, is_busy, owners):
        result = self.client._is_busy_snapshot(owners)

        self.assertEqual(is_busy, result)

    @ddt.data(True, False)
    def test_get_snapshot(self, locked):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        mock_get_volume = self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value=volume))
        response = copy.deepcopy(fake.SNAPSHOTS_REST_RESPONSE)
        owners = ['volume_clone'] if locked else []
        response['records'][0]['owners'] = owners
        mock_send_request = self.mock_object(self.client, 'send_request',
                                             mock.Mock(return_value=response))
        mock_has_records = self.mock_object(
            self.client, '_has_records', mock.Mock(return_value=True))

        mock_is_busy = self.mock_object(self.client, '_is_busy_snapshot',
                                        mock.Mock(return_value=True))

        result = self.client.get_snapshot(fake.VOLUME_NAMES[0],
                                          fake.SNAPSHOT_NAME)

        expected_snapshot = {
            'access-time': fake.SNAPSHOT_REST['create_time'],
            'name': fake.SNAPSHOT_REST['name'],
            'volume': fake.SNAPSHOT_REST['volume']['name'],
            'owners': set(owners),
            'busy': True,
            'locked_by_clone': locked,
        }
        self.assertEqual(expected_snapshot, result)
        mock_get_volume.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        uuid = volume['uuid']
        query = {
            'name': fake.SNAPSHOT_NAME,
            'fields': 'name,volume,create_time,owners'
        }
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}/snapshots', 'get', query=query)
        mock_has_records.assert_called_once_with(response)
        mock_is_busy.assert_called_once_with(set(owners))

    def test_get_snapshot_raise_not_found(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value=volume))
        self.mock_object(
            self.client, 'send_request',
            mock.Mock(return_value=fake.NO_RECORDS_RESPONSE_REST))
        self.mock_object(
            self.client, '_has_records', mock.Mock(return_value=False))

        self.assertRaises(
            exception.SnapshotResourceNotFound,
            self.client.get_snapshot,
            fake.VOLUME_NAMES[0],
            fake.SNAPSHOT_NAME)

    def test_get_snapshot_raise_more_than_one(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value=volume))
        self.mock_object(
            self.client, 'send_request',
            mock.Mock(return_value=fake.SNAPSHOTS_MULTIPLE_REST_RESPONSE))
        self.mock_object(
            self.client, '_has_records', mock.Mock(return_value=True))

        self.assertRaises(
            exception.NetAppException,
            self.client.get_snapshot,
            fake.VOLUME_NAMES[0],
            fake.SNAPSHOT_NAME)

    def test_get_clone_children_for_snapshot(self):
        mock_get_records = self.mock_object(
            self.client, 'get_records',
            mock.Mock(return_value=fake.VOLUME_LIST_SIMPLE_RESPONSE_REST))

        result = self.client.get_clone_children_for_snapshot(
            fake.VOLUME_NAMES[0], fake.SNAPSHOT_NAME)

        expected_children = [{'name': fake.VOLUME_NAMES[0]}]
        self.assertEqual(expected_children, result)
        query = {
            'clone.parent_snapshot.name': fake.SNAPSHOT_NAME,
            'clone.parent_volume.name': fake.VOLUME_NAMES[0],
            'fields': 'name'
        }
        mock_get_records.assert_called_once_with(
            '/storage/volumes', query=query)

    def test_volume_clone_split_start(self):
        fake_resp_vol = fake.REST_SIMPLE_RESPONSE["records"][0]
        fake_uuid = fake_resp_vol['uuid']
        mock_get_unique_volume = self.mock_object(
            self.client, "_get_volume_by_args",
            mock.Mock(return_value=fake_resp_vol)
        )
        mock_send_request = self.mock_object(
            self.client, 'send_request',
            mock.Mock(return_value=fake.VOLUME_LIST_SIMPLE_RESPONSE_REST))

        self.client.volume_clone_split_start(fake.VOLUME_NAMES[0])
        mock_get_unique_volume.assert_called_once()
        body = {
            'clone.split_initiated': 'true',
        }
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{fake_uuid}', 'patch', body=body,
            wait_on_accepted=False)

    def test_volume_clone_split_stop(self):
        fake_resp_vol = fake.REST_SIMPLE_RESPONSE["records"][0]
        fake_uuid = fake_resp_vol['uuid']
        mock_get_unique_volume = self.mock_object(
            self.client, "_get_volume_by_args",
            mock.Mock(return_value=fake_resp_vol)
        )
        mock_send_request = self.mock_object(
            self.client, 'send_request',
            mock.Mock(return_value=fake.VOLUME_LIST_SIMPLE_RESPONSE_REST))

        self.client.volume_clone_split_stop(fake.VOLUME_NAMES[0])
        mock_get_unique_volume.assert_called_once()
        body = {
            'clone.split_initiated': 'false',
        }
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{fake_uuid}', 'patch', body=body,
            wait_on_accepted=False)

    def test_rename_snapshot(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        mock_get_volume = self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value=volume))
        mock_send_request = self.mock_object(self.client, 'send_request')

        self.client.rename_snapshot(
            fake.VOLUME_NAMES[0], fake.SNAPSHOT_NAME,
            'new_' + fake.SNAPSHOT_NAME)

        mock_get_volume.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0])
        query = {
            'name': fake.SNAPSHOT_NAME,
        }
        body = {
            'name': 'new_' + fake.SNAPSHOT_NAME,
        }
        uuid = volume['uuid']
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}/snapshots', 'patch', query=query,
            body=body)

    def test__get_soft_deleted_snapshots(self):
        mock_get_records = self.mock_object(
            self.client, 'get_records',
            mock.Mock(return_value=fake.SNAPSHOTS_MULTIPLE_REST_RESPONSE))
        self.mock_object(
            self.client, '_is_busy_snapshot',
            mock.Mock(side_effect=[True, False]))

        snapshots_map = self.client._get_soft_deleted_snapshots()

        expected_snapshots = {
            fake.VSERVER_NAME: [{
                "uuid": fake.FAKE_SNAPSHOT_UUID,
                "volume_uuid": fake.FAKE_VOLUME_UUID,
            }]
        }
        self.assertEqual(expected_snapshots, snapshots_map)
        query = {
            'name': 'deleted_manila_*',
            'fields': 'uuid,volume,owners,svm.name'
        }
        mock_get_records.assert_called_once_with(
            '/storage/volumes/*/snapshots', query=query)

    @ddt.data(True, False)
    def test_prune_deleted_snapshots(self, fail_deleting):
        soft_deleted_snapshots = {
            fake.VSERVER_NAME: [{
                "uuid": fake.FAKE_SNAPSHOT_UUID,
                "volume_uuid": fake.FAKE_VOLUME_UUID,
            }]
        }
        mock_get_snaps = self.mock_object(
            self.client, '_get_soft_deleted_snapshots',
            mock.Mock(return_value=soft_deleted_snapshots)
        )
        if fail_deleting:
            mock_send_request = self.mock_object(
                self.client, 'send_request',
                mock.Mock(side_effect=netapp_api.api.NaApiError))
        else:
            mock_send_request = self.mock_object(self.client, 'send_request')

        self.client.prune_deleted_snapshots()

        mock_get_snaps.assert_called_once_with()
        vol_uuid = fake.FAKE_VOLUME_UUID
        snap_uuid = fake.FAKE_SNAPSHOT_UUID
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{vol_uuid}/snapshots/{snap_uuid}', 'delete')

    @ddt.data(True, False)
    def test_snapshot_exists(self, exists):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        vol_uuid = volume['uuid']
        mock_get_vol = self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value=volume))
        mock_send_request = self.mock_object(
            self.client, 'send_request',
            mock.Mock(return_value=fake.SNAPSHOTS_REST_RESPONSE))
        mock_has_records = self.mock_object(self.client, '_has_records',
                                            mock.Mock(return_value=exists))

        res = self.client.snapshot_exists(fake.SNAPSHOT_NAME,
                                          fake.VOLUME_NAMES[0])

        self.assertEqual(exists, res)
        mock_get_vol.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0], fields='uuid,state')
        query = {
            'name': fake.SNAPSHOT_NAME
        }
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{vol_uuid}/snapshots/', 'get', query=query)
        mock_has_records.assert_called_once_with(fake.SNAPSHOTS_REST_RESPONSE)

    def test_snapshot_exists_error(self):
        volume = {'state': 'offline'}
        self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value=volume))

        self.assertRaises(
            exception.SnapshotUnavailable,
            self.client.snapshot_exists,
            fake.SNAPSHOT_NAME, fake.VOLUME_NAMES[0])

    @ddt.data('source', 'destination', None)
    def test_volume_has_snapmirror_relationships(self, snapmirror_rel_type):
        """Snapmirror relationships can be both ways."""

        vol = fake.FAKE_MANAGE_VOLUME
        snapmirror = {
            'source-vserver': fake.SM_SOURCE_VSERVER,
            'source-volume': fake.SM_SOURCE_VOLUME,
            'destination-vserver': fake.SM_DEST_VSERVER,
            'destination-volume': fake.SM_DEST_VOLUME,
            'mirror-state': 'snapmirrored',
            'schedule': 'daily',
        }
        expected_get_snapmirrors_call_count = 2
        expected_get_snapmirrors_calls = [
            mock.call(source_vserver=vol['owning-vserver-name'],
                      source_volume=vol['name']),
            mock.call(dest_vserver=vol['owning-vserver-name'],
                      dest_volume=vol['name']),
        ]
        if snapmirror_rel_type is None:
            side_effect = ([], [])
        elif snapmirror_rel_type == 'source':
            snapmirror['source-vserver'] = vol['owning-vserver-name']
            snapmirror['source-volume'] = vol['name']
            side_effect = ([snapmirror], None)
            expected_get_snapmirrors_call_count = 1
            expected_get_snapmirrors_calls.pop()
        else:
            snapmirror['destination-vserver'] = vol['owning-vserver-name']
            snapmirror['destination-volume'] = vol['name']
            side_effect = (None, [snapmirror])
        mock_get_snapmirrors_call = self.mock_object(
            self.client, 'get_snapmirrors', mock.Mock(side_effect=side_effect))
        mock_exc_log = self.mock_object(client_cmode.LOG, 'exception')
        expected_retval = True if snapmirror_rel_type else False

        retval = self.client.volume_has_snapmirror_relationships(vol)

        self.assertEqual(expected_retval, retval)
        self.assertEqual(expected_get_snapmirrors_call_count,
                         mock_get_snapmirrors_call.call_count)
        mock_get_snapmirrors_call.assert_has_calls(
            expected_get_snapmirrors_calls)
        self.assertFalse(mock_exc_log.called)

    def test_volume_has_snapmirror_relationships_api_error(self):

        vol = fake.FAKE_MANAGE_VOLUME
        expected_get_snapmirrors_calls = [
            mock.call(source_vserver=vol['owning-vserver-name'],
                      source_volume=vol['name']),
        ]
        mock_get_snapmirrors_call = self.mock_object(
            self.client, 'get_snapmirrors', mock.Mock(
                side_effect=self._mock_api_error()))
        mock_exc_log = self.mock_object(client_cmode_rest.LOG, 'exception')

        retval = self.client.volume_has_snapmirror_relationships(vol)

        self.assertFalse(retval)
        self.assertEqual(1, mock_get_snapmirrors_call.call_count)
        mock_get_snapmirrors_call.assert_has_calls(
            expected_get_snapmirrors_calls)
        self.assertTrue(mock_exc_log.called)

    def test_get_snapmirrors_svm(self):
        return_get_snp = fake.REST_GET_SNAPMIRRORS_RESPONSE

        mock_get_snap = self.mock_object(
            self.client, 'get_snapmirrors',
            mock.Mock(return_value=return_get_snp))

        res = self.client.get_snapmirrors_svm(fake.SM_SOURCE_VSERVER,
                                              fake.SM_DEST_VSERVER,
                                              None)

        mock_get_snap.assert_called_once_with(
            source_path=fake.SM_SOURCE_VSERVER + ':*',
            dest_path=fake.SM_DEST_VSERVER + ':*',
            desired_attributes=None)
        self.assertEqual(return_get_snp, res)

    def test_get_snapmirrors(self):

        api_response = fake.SNAPMIRROR_GET_ITER_RESPONSE_REST
        mock_send_request = self.mock_object(
            self.client,
            'send_request',
            mock.Mock(return_value=api_response))

        result = self.client.get_snapmirrors(
            fake.SM_SOURCE_PATH, fake.SM_DEST_PATH,
            fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
            enable_tunneling=True)

        expected = fake.REST_GET_SNAPMIRRORS_RESPONSE

        query = {
            'source.path': (fake.SM_SOURCE_VSERVER + ':' +
                            fake.SM_SOURCE_VOLUME),
            'destination.path': (fake.SM_DEST_VSERVER +
                                 ':' + fake.SM_DEST_VOLUME),
            'fields': 'state,source.svm.name,source.path,destination.svm.name,'
                      'destination.path,transfer.end_time,uuid,policy.type,'
                      'policy.name,transfer_schedule.name,transfer.state,'
                      'last_transfer_type,transfer.bytes_transferred,healthy'
        }

        mock_send_request.assert_called_once_with('/snapmirror/relationships',
                                                  'get', query=query,
                                                  enable_tunneling=True)
        self.assertEqual(expected, result)

    @ddt.data(
        {'source_path': fake.SM_SOURCE_PATH, 'dest_path': fake.SM_DEST_PATH},
        {'source_path': None, 'dest_path': None})
    @ddt.unpack
    def test__get_snapmirrors(self, source_path, dest_path):

        api_response = fake.SNAPMIRROR_GET_ITER_RESPONSE_REST
        mock_send_request = self.mock_object(
            self.client,
            'send_request',
            mock.Mock(return_value=api_response))

        result = self.client._get_snapmirrors(
            source_path, dest_path,
            fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)

        query = {
            'source.path': (fake.SM_SOURCE_VSERVER + ':' +
                            fake.SM_SOURCE_VOLUME),
            'destination.path': (fake.SM_DEST_VSERVER +
                                 ':' + fake.SM_DEST_VOLUME),
            'fields': 'state,source.svm.name,source.path,destination.svm.name,'
                      'destination.path,transfer.end_time,uuid,policy.type,'
                      'policy.name,transfer_schedule.name,transfer.state,'
                      'last_transfer_type,transfer.bytes_transferred,healthy'
        }

        mock_send_request.assert_called_once_with('/snapmirror/relationships',
                                                  'get', query=query,
                                                  enable_tunneling=True)
        self.assertEqual(1, len(result))

    def test__get_snapmirrors_not_found(self):

        api_response = fake.NO_RECORDS_RESPONSE_REST
        mock_send_request = self.mock_object(
            self.client,
            'send_request',
            mock.Mock(return_value=api_response))

        result = self.client._get_snapmirrors(
            fake.SM_SOURCE_PATH, fake.SM_DEST_PATH,
            fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)

        query = {
            'source.path': (fake.SM_SOURCE_VSERVER + ':' +
                            fake.SM_SOURCE_VOLUME),
            'destination.path': (fake.SM_DEST_VSERVER +
                                 ':' + fake.SM_DEST_VOLUME),
            'fields': 'state,source.svm.name,source.path,destination.svm.name,'
                      'destination.path,transfer.end_time,uuid,policy.type,'
                      'policy.name,transfer_schedule.name,transfer.state,'
                      'last_transfer_type,transfer.bytes_transferred,healthy'
        }

        mock_send_request.assert_called_once_with('/snapmirror/relationships',
                                                  'get', query=query,
                                                  enable_tunneling=True)
        self.assertEqual([], result)

    @ddt.data(True, False)
    def test_modify_volume_no_optional_args(self, is_flexgroup):

        self.mock_object(self.client, 'send_request')
        mock_update_volume_efficiency_attributes = self.mock_object(
            self.client, 'update_volume_efficiency_attributes')

        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, '_is_snaplock_enabled_volume',
                         mock.Mock(return_value=True))
        aggr = fake.SHARE_AGGREGATE_NAME
        if is_flexgroup:
            aggr = list(fake.SHARE_AGGREGATE_NAMES)

        self.client.modify_volume(aggr, fake.SHARE_NAME)

        # default body for call with no optional params
        body = {'guarantee': {'type': 'volume'}}
        self.client.send_request.assert_called_once_with(
            '/storage/volumes/' + volume['uuid'], 'patch', body=body)
        mock_update_volume_efficiency_attributes.assert_called_once_with(
            fake.SHARE_NAME, False, False,
            is_flexgroup=is_flexgroup, efficiency_policy=None
        )

    @ddt.data((fake.QOS_POLICY_GROUP_NAME, None),
              (None, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME))
    @ddt.unpack
    def test_modify_volume_all_optional_args(self, qos_group,
                                             adaptive_qos_group):
        self.client.features.add_feature('ADAPTIVE_QOS')
        self.mock_object(self.client, 'send_request')
        mock_update_volume_efficiency_attributes = self.mock_object(
            self.client, 'update_volume_efficiency_attributes')

        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}
        self.mock_object(self.client, '_is_snaplock_enabled_volume',
                         mock.Mock(return_value=True))

        self.client.modify_volume(
            fake.SHARE_AGGREGATE_NAME,
            fake.SHARE_NAME,
            thin_provisioned=True,
            snapshot_policy=fake.SNAPSHOT_POLICY_NAME,
            language=fake.LANGUAGE,
            dedup_enabled=True,
            compression_enabled=False,
            max_files=fake.MAX_FILES,
            qos_policy_group=qos_group,
            adaptive_qos_policy_group=adaptive_qos_group,
            autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS,
            hide_snapdir=True,
            **options
        )

        qos_policy_name = qos_group or adaptive_qos_group
        body = {
            'guarantee': {'type': 'none'},
            'autosize': {
                'mode': 'off',
                'grow_threshold': '85',
                'shrink_threshold': '50',
                'maximum': '1258288',
                'minimum': '1048576'
            },
            'files': {'maximum': 5000},
            'snapshot_policy': {'name': 'fake_snapshot_policy'},
            'qos': {'policy': {'name': qos_policy_name}},
            'snapshot_directory_access_enabled': 'false',
            'language': 'fake_language'
        }

        self.client.send_request.assert_called_once_with(
            '/storage/volumes/' + volume['uuid'], 'patch', body=body)
        mock_update_volume_efficiency_attributes.assert_called_once_with(
            fake.SHARE_NAME, True, False,
            is_flexgroup=False,
            efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME
        )

    def test__parse_timestamp(self):
        test_time_str = '2022-11-25T14:41:20+00:00'
        res = self.client._parse_timestamp(test_time_str)
        self.assertEqual(1669387280.0, res)

    def test__parse_timestamp_exception(self):
        test_time_str = None
        self.assertRaises(TypeError,
                          self.client._parse_timestamp,
                          test_time_str)

    def test__build_autosize_attributes(self):
        """Test _build_autosize_attributes with various input scenarios."""

        # Test case 1: Basic functionality with all supported attributes
        autosize_attrs = {
            'grow-threshold-percent': 90,
            'shrink-threshold-percent': 50,
            'maximum-size': '10GB',
            'minimum-size': '1GB',
            'mode': 'grow'
        }

        result = self.client._build_autosize_attributes(autosize_attrs)

        expected = {
            'grow_threshold': 90,
            'shrink_threshold': 50,
            'maximum': '10GB',
            'minimum': '1GB',
            'mode': 'grow'
        }
        self.assertEqual(expected, result)

    def test__build_autosize_attributes_partial_attrs(self):
        """Test _build_autosize_attributes with only some attributes."""
        autosize_attrs = {
            'grow-threshold-percent': 85,
            'maximum-size': '5GB'
        }

        result = self.client._build_autosize_attributes(autosize_attrs)

        expected = {
            'grow_threshold': 85,
            'maximum': '5GB'
        }
        self.assertEqual(expected, result)

    def test__build_autosize_attributes_empty_dict(self):
        """Test _build_autosize_attributes returns None for empty dict."""
        autosize_attrs = {}

        result = self.client._build_autosize_attributes(autosize_attrs)

        self.assertIsNone(result)

    def test__build_autosize_attributes_with_mode_only(self):
        """Test _build_autosize_attributes with only mode attribute."""
        autosize_attrs = {
            'mode': 'grow_shrink'
        }

        result = self.client._build_autosize_attributes(autosize_attrs)

        expected = {
            'mode': 'grow_shrink'
        }
        self.assertEqual(expected, result)
        autosize_attrs = {
            'grow-threshold-percent': 90,
            'maximum-size': '10GB'
        }

        result = self.client._build_autosize_attributes(autosize_attrs)

        expected = {
            'grow_threshold': 90,
            'maximum': '10GB'
        }
        self.assertEqual(expected, result)

    def test_start_volume_move(self):

        mock__send_volume_move_request = self.mock_object(
            self.client, '_send_volume_move_request')

        self.client.start_volume_move(fake.VOLUME_NAMES[0], fake.VSERVER_NAME,
                                      fake.SHARE_AGGREGATE_NAME,
                                      'fake_cutover', False, True)

        mock__send_volume_move_request.assert_called_once_with(
            fake.VOLUME_NAMES[0], fake.VSERVER_NAME, fake.SHARE_AGGREGATE_NAME,
            cutover_action='fake_cutover', encrypt_destination=False,
            dest_aggr_encryption=True)

    def test_check_volume_move(self):

        mock__send_volume_move_request = self.mock_object(
            self.client, '_send_volume_move_request')

        self.client.check_volume_move(fake.VOLUME_NAMES[0], fake.VSERVER_NAME,
                                      fake.SHARE_AGGREGATE_NAME, False, True)

        mock__send_volume_move_request.assert_called_once_with(
            fake.VOLUME_NAMES[0], fake.VSERVER_NAME, fake.SHARE_AGGREGATE_NAME,
            validation_only=True, encrypt_destination=False,
            dest_aggr_encryption=True)

    def test__send_volume_move_request(self):
        mock_sr = self.mock_object(self.client, 'send_request')
        self.client._send_volume_move_request('volume_name', 'vserver',
                                              'destination_aggregate',
                                              cutover_action='wait',
                                              validation_only=True,
                                              encrypt_destination=False,
                                              dest_aggr_encryption=True)
        query = {'name': 'volume_name'}
        body = {
            'movement.destination_aggregate.name': 'destination_aggregate',
            'validate_only': 'true',
            'movement.state': 'wait',
        }
        mock_sr.assert_called_once_with(
            '/storage/volumes/', 'patch', query=query, body=body,
            wait_on_accepted=False)

    def test_get_nfs_export_policy_for_volume(self):

        fake_query = {
            'name': 'fake_volume_name',
            'fields': 'nas.export_policy.name'
        }

        ret = {
            'records': [
                {
                    'nas': {
                        'export_policy': {
                            'name': 'fake_name'
                        }
                    }
                }
            ]
        }

        mock_records = self.mock_object(self.client, '_has_records',
                                        mock.Mock(return_value=True))
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=ret))

        res = self.client.get_nfs_export_policy_for_volume('fake_volume_name')

        mock_records.assert_called_once_with(ret)
        mock_sr.assert_called_once_with('/storage/volumes/', 'get',
                                        query=fake_query)
        expected = 'fake_name'
        self.assertEqual(expected, res)

    def test_get_unique_export_policy_id(self):
        mock_records = self.mock_object(self.client, '_has_records',
                                        mock.Mock(return_value=True))
        expected = 'fake_uuid'
        ret = {
            'records': [
                {
                    'id': 'fake_uuid'
                }
            ]
        }
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=ret))
        res = self.client.get_unique_export_policy_id('fake_policy_name')
        mock_records.assert_called_once_with(ret)
        mock_sr.assert_called_once_with(
            '/protocols/nfs/export-policies', 'get',
            query={'name': 'fake_policy_name'})
        self.assertEqual(expected, res)

    def test__get_nfs_export_rule_indices(self):
        mockpid = self.mock_object(self.client, 'get_unique_export_policy_id',
                                   mock.Mock(return_value='fake_policy_id'))

        fake_uuid = 'fake_policy_id'

        fake_query = {
            'clients.match': 'fakecl',
            'fields': 'clients.match,index'
        }

        ret = {
            'records': [
                {
                    'index': '0'
                }
            ]
        }

        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=ret))
        res = self.client._get_nfs_export_rule_indices('fake_policy', 'fakecl')
        mockpid.assert_called_once_with('fake_policy')
        mock_sr.assert_called_once_with(
            f'/protocols/nfs/export-policies/{fake_uuid}/rules', 'get',
            query=fake_query)
        expected = ['0']
        self.assertEqual(expected, res)

    def test__add_nfs_export_rule(self):
        mockpid = self.mock_object(self.client, 'get_unique_export_policy_id',
                                   mock.Mock(return_value='fake_policy_id'))
        mock_sr = self.mock_object(self.client, 'send_request')
        self.client._add_nfs_export_rule('fake_policy', 'fakecl', False,
                                         ['rw'])
        mockpid.assert_called_once_with('fake_policy')

        body = {
            'clients': [{'match': 'fakecl'}],
            'ro_rule': ['rw'],
            'rw_rule': ['rw'],
            'superuser': ['rw']
        }
        mock_sr.assert_called_once_with(
            '/protocols/nfs/export-policies/fake_policy_id/rules',
            'post', body=body)

    def test__update_nfs_export_rule(self):

        fake_body = {
            'client_match': 'fake_cli',
            'ro_rule': ['rw'],
            'rw_rule': ['rw'],
            'superuser': ['rw']
        }

        mockpid = self.mock_object(self.client, 'get_unique_export_policy_id',
                                   mock.Mock(return_value='fake_policy_id'))
        mock_sr = self.mock_object(self.client, 'send_request')
        self.client._update_nfs_export_rule('fake_policy', 'fake_cli', False,
                                            '0', ['rw'])
        mockpid.assert_called_once_with('fake_policy')
        mock_sr.assert_called_once_with(
            '/protocols/nfs/export-policies/fake_policy_id/rules/0',
            'patch', body=fake_body)

    def test__remove_nfs_export_rules(self):

        fake_body = {
            'index': 0
        }

        mockpid = self.mock_object(self.client, 'get_unique_export_policy_id',
                                   mock.Mock(return_value='fake_policy_id'))
        mock_sr = self.mock_object(self.client, 'send_request')
        self.client._remove_nfs_export_rules('fake_policy', [0])
        mockpid.assert_called_once_with('fake_policy')
        mock_sr.assert_called_once_with(
            '/protocols/nfs/export-policies/fake_policy_id/rules/0', 'delete',
            body=fake_body)

    def test_modify_cifs_share_access(self):
        return_uuid = fake.GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_uuid))
        self.client.modify_cifs_share_access(fake.SHARE_NAME, fake.USER_NAME,
                                             'read')
        fake_user = 'fake_user'
        FAKE_CIFS_USER_GROUP_TYPE = 'windows'
        fake_uuid = 'fake_uuid'
        fake_share = fake.SHARE_NAME
        query = {'name': 'fake_share'}
        body = {'permission': 'read'}

        self.client.send_request.assert_has_calls([
            mock.call('/protocols/cifs/shares', 'get', query=query),
            mock.call(f'/protocols/cifs/shares/{fake_uuid}/{fake_share}'
                      f'/acls/{fake_user}/{FAKE_CIFS_USER_GROUP_TYPE}',
                      'patch', body=body)])

    def test_add_cifs_share_access(self):
        return_uuid = fake.GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_uuid))
        self.client.add_cifs_share_access(fake.SHARE_NAME,
                                          fake.USER_NAME, 'read')
        fake_uuid = "fake_uuid"
        query = {'name': 'fake_share'}
        body = {'permission': 'read',
                'user_or_group': 'fake_user'}
        self.client.send_request.assert_has_calls([
            mock.call('/protocols/cifs/shares', 'get', query=query),
            mock.call(f'/protocols/cifs/shares/{fake_uuid}/{fake.SHARE_NAME}'
                      '/acls', 'post', body=body)])

    def test_get_cifs_share_access_rules_empty(self):
        return_uuid = fake.GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_uuid))

    def test_get_cifs_share_access_rules_not_empty(self):
        return_uuid = fake.GENERIC_EXPORT_POLICY_RESPONSE_AND_VOLUMES
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_uuid))

        rules = {}

        fake_results = fake.FAKE_CIFS_RECORDS

        for record in fake_results['records']:
            user_or_group = record['user_or_group']
            permission = record['permission']
            rules[user_or_group] = permission

    def test_mount_volume_with_junction_path(self):
        volume_name = fake.SHARE_NAME
        junction_path = 'fake_path'
        volume = fake.VOLUME

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.client.mount_volume(volume_name, junction_path=junction_path)

        uuid = volume['uuid']

        body = {
            'nas.path': '/%s' % junction_path
        }

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)

    def test_mount_volume_with_volume_name(self):
        volume_name = fake.SHARE_NAME
        volume = fake.VOLUME

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.client.mount_volume(volume_name)

        uuid = volume['uuid']

        body = {
            'nas.path': '/%s' % volume_name
        }

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)

    def test_set_volume_name(self):
        volume_name = fake.SHARE_NAME
        new_volume_name = 'fake_name'

        volume = fake.VOLUME

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request')

        self.client.set_volume_name(volume_name, new_volume_name)

        uuid = volume['uuid']

        body = {
            'name': new_volume_name
        }

        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{uuid}', 'patch', body=body)

    def test_get_job(self):
        mock_sr = self.mock_object(self.client, 'send_request')
        self.client.get_job('fake_job_uuid')
        mock_sr.assert_called_once_with('/cluster/jobs/fake_job_uuid',
                                        'get', enable_tunneling=False)

    @ddt.data(netapp_api.EREST_VSERVER_NOT_FOUND, 'fake')
    def test_vserver_exists_exception(self, er):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error(code=er)))
        if er == netapp_api.EREST_VSERVER_NOT_FOUND:
            result = self.client.vserver_exists(fake.VSERVER_NAME)
            self.assertFalse(result)
        else:
            self.assertRaises(netapp_api.api.NaApiError,
                              self.client.vserver_exists,
                              fake.VSERVER_NAME)

    def test__get_aggregate_disk_types(self):
        response = fake.FAKE_DISK_TYPE_RESPONSE
        aggr = fake.SHARE_AGGREGATE_NAME
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=response))
        query = {
            'aggregates.name': aggr,
            'fields': 'effective_type'
        }
        expected = {'fakedisk'}

        result = self.client._get_aggregate_disk_types(aggr)

        mock_sr.assert_called_once_with('/storage/disks', 'get', query=query)
        self.assertEqual(expected, result)

    def test__get_aggregate_disk_types_exception(self):
        aggr = fake.SHARE_AGGREGATE_NAME
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        result = self.client._get_aggregate_disk_types(aggr)
        self.assertEqual(set(), result)

    def test_create_nfs_export_policy_exception(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.assertRaises(netapp_api.api.NaApiError,
                          self.client.create_nfs_export_policy,
                          fake.EXPORT_POLICY_NAME)

    @ddt.data(True, False)
    def test__get_create_volume_body(self, thin_provisioned):
        expected = {
            'type': 'fake_type',
            'guarantee.type': ('none' if thin_provisioned else 'volume'),
            'nas.path': '/%s' % fake.SHARE_MOUNT_POINT,
            'snapshot_policy.name': fake.SNAPSHOT_POLICY_NAME,
            'language': 'fake_language',
            'space.snapshot.reserve_percent': 'fake_percent',
            'qos.policy.name': fake.QOS_POLICY_GROUP_NAME,
            'svm.name': 'fake_vserver',
            'encryption.enabled': 'true',
            'snaplock.type': 'compliance',
        }

        self.mock_object(self.client.connection, 'get_vserver',
                         mock.Mock(return_value='fake_vserver'))
        res = self.client._get_create_volume_body(fake.VOLUME_NAMES[0],
                                                  thin_provisioned,
                                                  fake.SNAPSHOT_POLICY_NAME,
                                                  'fake_language',
                                                  'fake_percent',
                                                  'fake_type',
                                                  fake.QOS_POLICY_GROUP_NAME,
                                                  True,
                                                  fake.QOS_POLICY_GROUP_NAME,
                                                  fake.SHARE_MOUNT_POINT,
                                                  "compliance",
                                                  True)
        self.assertEqual(expected, res)

    def test_get_job_state(self):
        expected = 'success'
        query = {
            'uuid': 'fake_uuid',
            'fields': 'state'
        }
        response = {
            'records': [fake.JOB_SUCCESSFUL_REST]
        }
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        result = self.client.get_job_state('fake_uuid')
        mock_sr.assert_called_once_with('/cluster/jobs/', 'get', query=query,
                                        enable_tunneling=False)
        self.assertEqual(expected, result)

    def test_get_job_state_not_found(self):
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=False))
        self.assertRaises(exception.NetAppException,
                          self.client.get_job_state,
                          'fake_uuid')

    def test_update_volume_snapshot_policy(self):
        return_uuid = {
            'uuid': 'fake_uuid'
        }
        mock_get_vol = self.mock_object(self.client, '_get_volume_by_args',
                                        mock.Mock(return_value=return_uuid))
        mock_sr = self.mock_object(self.client, 'send_request')

        self.client.update_volume_snapshot_policy('fake_volume_name',
                                                  fake.SNAPSHOT_POLICY_NAME)
        body = {
            'snapshot_policy.name': fake.SNAPSHOT_POLICY_NAME
        }
        mock_sr.assert_called_once_with('/storage/volumes/fake_uuid',
                                        'patch', body=body)
        mock_get_vol.assert_called_once_with(vol_name='fake_volume_name')

    @ddt.data(True, False)
    def test_update_volume_efficiency_attributes(self, status):
        response = {
            'dedupe': not status,
            'compression': not status
        }
        self.mock_object(self.client, 'get_volume_efficiency_status',
                         mock.Mock(return_value=response))
        en_dedupe = self.mock_object(self.client, 'enable_dedupe_async')
        dis_dedupe = self.mock_object(self.client, 'disable_dedupe_async')
        en_comp = self.mock_object(self.client, 'enable_compression_async')
        dis_comp = self.mock_object(self.client, 'disable_compression_async')
        apply_efficiency_policy = self.mock_object(
            self.client, 'apply_volume_efficiency_policy'
        )

        self.client.update_volume_efficiency_attributes(
            fake.VOLUME_NAMES[0],
            status, status,
            efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME)

        if status:
            en_dedupe.assert_called_once_with(fake.VOLUME_NAMES[0])
            en_comp.assert_called_once_with(fake.VOLUME_NAMES[0])
            apply_efficiency_policy.assert_called_once_with(
                fake.VOLUME_NAMES[0],
                efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME
            )
        else:
            dis_dedupe.assert_called_once_with(fake.VOLUME_NAMES[0])
            dis_comp.assert_called_once_with(fake.VOLUME_NAMES[0])
            apply_efficiency_policy.assert_called_once_with(
                fake.VOLUME_NAMES[0],
                efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME
            )

    def test_trigger_volume_move_cutover(self):
        query = {
            'name': fake.VOLUME_NAMES[0]
        }
        body = {
            'movement.state': 'cutover'
        }
        self.mock_object(self.client, 'send_request')
        self.client.trigger_volume_move_cutover(
            fake.VOLUME_NAMES[0], fake.VSERVER_NAME)
        self.client.send_request.assert_called_once_with(
            '/storage/volumes/', 'patch', query=query,
            body=body)

    def test_abort_volume_move(self):
        return_uuid = {
            'uuid': 'fake_uuid'
        }
        mock_get_vol = self.mock_object(self.client, '_get_volume_by_args',
                                        mock.Mock(return_value=return_uuid))
        mock_sr = self.mock_object(self.client, 'send_request')

        self.client.abort_volume_move('fake_volume_name', 'fake_vserver')

        mock_sr.assert_called_once_with('/storage/volumes/fake_uuid', 'patch')
        mock_get_vol.assert_called_once_with(vol_name='fake_volume_name')

    def test_get_volume_move_status(self):
        """Gets the current state of a volume move operation."""

        return_sr = fake.FAKE_VOL_MOVE_STATUS

        fields = 'movement.percent_complete,movement.state'

        query = {
            'name': 'fake_name',
            'svm.name': 'fake_svm',
            'fields': fields
        }

        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=return_sr))

        result = self.client.get_volume_move_status('fake_name', 'fake_svm')

        mock_sr.assert_called_once_with('/storage/volumes/',
                                        'get', query=query)

        volume_move_info = return_sr.get('records')[0]
        volume_movement = volume_move_info['movement']

        expected = {
            'percent-complete': volume_movement['percent_complete'],
            'estimated-completion-time': '',
            'state': volume_movement['state'],
            'details': '',
            'cutover-action': '',
            'phase': volume_movement['state'],
        }

        self.assertEqual(expected, result)

    def test_list_snapmirror_snapshots(self):
        fake_response = fake.SNAPSHOTS_REST_RESPONSE
        api_response = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        mock_volume = self.mock_object(self.client,
                                       '_get_volume_by_args',
                                       mock.Mock(return_value=api_response))
        mock_request = self.mock_object(self.client, 'send_request',
                                        mock.Mock(return_value=fake_response))
        self.client.list_snapmirror_snapshots(fake.VOLUME_NAMES[0])

        query = {
            'owners': 'snapmirror_dependent',
        }
        mock_request.assert_called_once_with(
            '/storage/volumes/fake_uuid/snapshots/',
            'get', query=query)
        mock_volume.assert_called_once_with(vol_name=fake.VOLUME_NAMES[0])

    @ddt.data({'policy': 'fake_policy'},
              {'policy': None})
    @ddt.unpack
    def test_create_snapmirror_vol(self, policy):
        api_responses = [
            {
                "job": {
                    "uuid": fake.FAKE_UUID,
                },
            },
        ]
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=copy.deepcopy(api_responses)))
        self.client.create_snapmirror_vol(
            fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
            relationship_type=netapp_utils.EXTENDED_DATA_PROTECTION_TYPE,
            policy=policy)

        body = {
            'source': {
                'path': (fake.SM_SOURCE_VSERVER + ':' +
                         fake.SM_SOURCE_VOLUME),
            },
            'destination': {
                'path': (fake.SM_DEST_VSERVER + ':' +
                         fake.SM_DEST_VOLUME)
            }
        }

        if policy:
            body['policy.name'] = policy

        self.client.send_request.assert_has_calls([
            mock.call('/snapmirror/relationships/', 'post', body=body)])

    def test_create_snapmirror_vol_already_exists(self):
        api_responses = netapp_api.api.NaApiError(
            code=netapp_api.EREST_ERELATION_EXISTS)
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=api_responses))

        response = self.client.create_snapmirror_vol(
            fake.SM_SOURCE_VSERVER,
            fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER,
            fake.SM_DEST_VOLUME,
            schedule=None,
            policy=None,
            relationship_type='data_protection')
        self.assertIsNone(response)
        self.assertTrue(self.client.send_request.called)

    def test_create_snapmirror_vol_error(self):
        self.mock_object(
            self.client, 'send_request',
            mock.Mock(side_effect=netapp_api.api.NaApiError(code=123)))

        self.assertRaises(netapp_api.api.NaApiError,
                          self.client.create_snapmirror_vol,
                          fake.SM_SOURCE_VSERVER,
                          fake.SM_SOURCE_VOLUME,
                          fake.SM_DEST_VSERVER,
                          fake.SM_DEST_VOLUME,
                          schedule=None,
                          policy=None,
                          relationship_type='data_protection')
        self.assertTrue(self.client.send_request.called)

    def test__set_snapmirror_state(self):

        api_responses = [
            fake.SNAPMIRROR_GET_ITER_RESPONSE_REST,
            {
                "job":
                    {
                        "uuid": fake.FAKE_UUID
                    },
                "num_records": 1
            }
        ]

        expected_body = {'state': 'snapmirrored'}
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(side_effect=copy.deepcopy(api_responses)))

        result = self.client._set_snapmirror_state(
            'snapmirrored', None, None,
            fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)

        self.client.send_request.assert_has_calls([
            mock.call('/snapmirror/relationships/' + fake.FAKE_UUID,
                      'patch', body=expected_body, wait_on_accepted=True)])

        expected = {
            'operation-id': None,
            'status': None,
            'jobid': fake.FAKE_UUID,
            'error-code': None,
            'error-message': None,
            'relationship-uuid': fake.FAKE_UUID
        }
        self.assertEqual(expected, result)

    def test_initialize_snapmirror_vol(self):

        expected_job = {
            'operation-id': None,
            'status': None,
            'jobid': fake.FAKE_UUID,
            'error-code': None,
            'error-message': None,
        }

        mock_set_snapmirror_state = self.mock_object(
            self.client,
            '_set_snapmirror_state',
            mock.Mock(return_value=expected_job))

        result = self.client.initialize_snapmirror_vol(
            fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)

        mock_set_snapmirror_state.assert_called_once_with(
            'snapmirrored', None, None,
            fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
            wait_result=False)

        self.assertEqual(expected_job, result)

    def test_modify_snapmirror_vol(self):

        expected_job = {
            'operation-id': None,
            'status': None,
            'jobid': fake.FAKE_UUID,
            'error-code': None,
            'error-message': None,
        }

        mock_set_snapmirror_state = self.mock_object(
            self.client,
            '_set_snapmirror_state',
            mock.Mock(return_value=expected_job))

        result = self.client.modify_snapmirror_vol(
            fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
            None)

        mock_set_snapmirror_state.assert_called_once_with(
            None, None, None,
            fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
            fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
            wait_result=False, schedule=None)

        self.assertEqual(expected_job, result)

    def test__abort_snapmirror(self):
        return_snp = fake.REST_GET_SNAPMIRRORS_RESPONSE
        mock_get_snap = self.mock_object(self.client, '_get_snapmirrors',
                                         mock.Mock(return_value=return_snp))
        return_sr = fake.REST_SIMPLE_RESPONSE
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=return_sr))

        self.client._abort_snapmirror(fake.SM_SOURCE_PATH, fake.SM_DEST_PATH)

        mock_get_snap.assert_called_once_with(
            source_path=fake.SM_SOURCE_PATH,
            dest_path=fake.SM_DEST_PATH,
            source_vserver=None,
            source_volume=None,
            dest_vserver=None,
            dest_volume=None,
            enable_tunneling=None,
            list_destinations_only=None)

        mock_sr.assert_has_calls([
            mock.call(f'/snapmirror/relationships/{return_snp[0]["uuid"]}'
                      '/transfers/', 'get',
                      query={'state': 'transferring'}),
            mock.call(f'/snapmirror/relationships/{return_snp[0]["uuid"]}'
                      f'/transfers/{return_sr["records"][0]["uuid"]}',
                      'patch', body={'state': 'aborted'}),
        ])

    def test_abort_snapmirror_vol(self):
        mock_abort = self.mock_object(self.client, '_abort_snapmirror')
        self.client.abort_snapmirror_vol(fake.VSERVER_NAME,
                                         fake.VOLUME_NAMES[0],
                                         fake.VSERVER_NAME_2,
                                         fake.VOLUME_NAMES[1])
        mock_abort.assert_called_once_with(source_vserver=fake.VSERVER_NAME,
                                           source_volume=fake.VOLUME_NAMES[0],
                                           dest_vserver=fake.VSERVER_NAME_2,
                                           dest_volume=fake.VOLUME_NAMES[1],
                                           clear_checkpoint=False)

    def test_release_snapmirror_vol(self):
        mock_sr = self.mock_object(self.client, 'send_request')
        return_snp = fake.REST_GET_SNAPMIRRORS_RESPONSE
        mock_sd = self.mock_object(self.client, 'get_snapmirror_destinations',
                                   mock.Mock(return_value=return_snp))

        self.client.release_snapmirror_vol(fake.VSERVER_NAME,
                                           fake.VOLUME_NAMES[0],
                                           fake.VSERVER_NAME_2,
                                           fake.VOLUME_NAMES[1])

        mock_sd.assert_called_once_with(source_vserver=fake.VSERVER_NAME,
                                        source_volume=fake.VOLUME_NAMES[0],
                                        dest_vserver=fake.VSERVER_NAME_2,
                                        dest_volume=fake.VOLUME_NAMES[1],
                                        desired_attributes=['relationship-id'])

        uuid = return_snp[0].get("uuid")
        query = {"source_only": 'true'}
        mock_sr.assert_called_once_with(f'/snapmirror/relationships/{uuid}',
                                        'delete', query=query)

    def test_delete_snapmirror_no_records(self):
        query_uuid = {}
        query_uuid['source.path'] = (fake.SM_SOURCE_VSERVER + ':' +
                                     fake.SM_SOURCE_VOLUME)

        query_uuid['destination.path'] = (fake.SM_DEST_VSERVER + ':' +
                                          fake.SM_DEST_VOLUME)
        query_uuid['fields'] = 'uuid'

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake.NO_RECORDS_RESPONSE_REST))
        self.client._delete_snapmirror(fake.SM_SOURCE_VSERVER,
                                       fake.SM_SOURCE_VOLUME,
                                       fake.SM_DEST_VSERVER,
                                       fake.SM_DEST_VOLUME)
        self.client.send_request.assert_called_once_with(
            '/snapmirror/relationships/', 'get', query=query_uuid)

    def test_delete_snapmirror(self):
        query_uuid = {}
        query_uuid['source.path'] = (fake.SM_SOURCE_VSERVER + ':' +
                                     fake.SM_SOURCE_VOLUME)

        query_uuid['destination.path'] = (fake.SM_DEST_VSERVER + ':' +
                                          fake.SM_DEST_VOLUME)
        query_uuid['fields'] = 'uuid'
        fake_cluster = fake.FAKE_GET_CLUSTER_NODE_VERSION_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake_cluster))
        self.client._delete_snapmirror(fake.SM_SOURCE_VSERVER,
                                       fake.SM_SOURCE_VOLUME,
                                       fake.SM_DEST_VSERVER,
                                       fake.SM_DEST_VOLUME)

        query_delete = {"destination_only": "true"}
        snapmirror_uuid = fake_cluster.get('records')[0].get('uuid')
        self.client.send_request.assert_has_calls([
            mock.call('/snapmirror/relationships/', 'get', query=query_uuid),
            mock.call('/snapmirror/relationships/' + snapmirror_uuid, 'delete',
                      query=query_delete)
        ])

    def test_get_snapmirror_destinations(self):
        mock_get_sm = self.mock_object(self.client, '_get_snapmirrors')
        self.client.get_snapmirror_destinations(fake.SM_SOURCE_PATH,
                                                fake.SM_DEST_PATH,
                                                fake.SM_SOURCE_VSERVER,
                                                fake.SM_SOURCE_VOLUME,
                                                fake.SM_DEST_VSERVER,
                                                fake.SM_DEST_VOLUME)

        mock_get_sm.assert_called_once_with(
            source_path=fake.SM_SOURCE_PATH,
            dest_path=fake.SM_DEST_PATH,
            source_vserver=fake.SM_SOURCE_VSERVER,
            source_volume=fake.SM_SOURCE_VOLUME,
            dest_vserver=fake.SM_DEST_VSERVER,
            dest_volume=fake.SM_DEST_VOLUME,
            enable_tunneling=False,
            list_destinations_only=True)

    def test_delete_snapmirror_vol(self):
        mock_delete = self.mock_object(self.client, '_delete_snapmirror')
        self.client.delete_snapmirror_vol(fake.SM_SOURCE_VSERVER,
                                          fake.SM_SOURCE_VOLUME,
                                          fake.SM_DEST_VSERVER,
                                          fake.SM_DEST_VOLUME)
        mock_delete.assert_called_once_with(
            source_vserver=fake.SM_SOURCE_VSERVER,
            dest_vserver=fake.SM_DEST_VSERVER,
            source_volume=fake.SM_SOURCE_VOLUME,
            dest_volume=fake.SM_DEST_VOLUME)

    def test_disable_fpolicy_policy(self):
        query = {
            'name': fake.VSERVER_NAME,
            'fields': 'uuid'
        }
        response_svm = fake.SVMS_LIST_SIMPLE_RESPONSE_REST
        self.client.vserver = fake.VSERVER_NAME
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(side_effect=[response_svm, None]))

        self.client.disable_fpolicy_policy(fake.FPOLICY_POLICY_NAME)

        svm_id = response_svm.get('records')[0]['uuid']

        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get', query=query,
                      enable_tunneling=False),
            mock.call(f'/protocols/fpolicy/{svm_id}/policies'
                      f'/{fake.FPOLICY_POLICY_NAME}', 'patch')
        ])

    @ddt.data([fake.NO_RECORDS_RESPONSE_REST, None],
              [fake.SVMS_LIST_SIMPLE_RESPONSE_REST,
               netapp_api.api.NaApiError(code="1000", message="")])
    def test_disable_fpolicy_policy_failure(self, side_effect):
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(side_effect=side_effect))

        self.assertRaises(exception.NetAppException,
                          self.client.disable_fpolicy_policy,
                          fake.FPOLICY_POLICY_NAME)

    @ddt.data({'qos_policy_group_name': None,
               'adaptive_qos_policy_group_name': None},
              {'qos_policy_group_name': fake.QOS_POLICY_GROUP_NAME,
               'adaptive_qos_policy_group_name': None},
              {'qos_policy_group_name': None,
               'adaptive_qos_policy_group_name':
                   fake.ADAPTIVE_QOS_POLICY_GROUP_NAME},
              {'mount_point_name': None},
              )
    @ddt.unpack
    def test_create_volume_clone(self, qos_policy_group_name=None,
                                 adaptive_qos_policy_group_name=None,
                                 mount_point_name=None):
        self.mock_object(self.client, 'send_request')

        if qos_policy_group_name:
            volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
            uuid = volume["uuid"]
            self.mock_object(self.client,
                             '_get_volume_by_args',
                             mock.Mock(return_value=volume))
        self.mock_object(self.client, 'volume_clone_split_start')
        self.mock_object(
            self.client.connection, 'get_vserver',
            mock.Mock(return_value='fake_svm'))
        set_qos_adapt_mock = self.mock_object(
            self.client,
            'set_qos_adaptive_policy_group_for_volume')

        self.client.create_volume_clone(
            fake.SHARE_NAME,
            fake.PARENT_SHARE_NAME,
            fake.PARENT_SNAPSHOT_NAME,
            mount_point_name=mount_point_name,
            qos_policy_group=qos_policy_group_name,
            adaptive_qos_policy_group=adaptive_qos_policy_group_name)

        body = {
            'name': fake.SHARE_NAME,
            'clone.parent_volume.name': fake.PARENT_SHARE_NAME,
            'clone.parent_snapshot.name': fake.PARENT_SNAPSHOT_NAME,
            'nas.path': '/%s' % (mount_point_name or fake.SHARE_NAME),
            'clone.is_flexclone': 'true',
            'svm.name': 'fake_svm',
        }

        if adaptive_qos_policy_group_name is not None:
            set_qos_adapt_mock.assert_called_once_with(
                fake.SHARE_NAME, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME
            )

        if qos_policy_group_name:
            self.client._get_volume_by_args.assert_called_once_with(
                vol_name=fake.SHARE_NAME)
            self.client.send_request.assert_has_calls([
                mock.call('/storage/volumes', 'post', body=body),
                mock.call(f'/storage/volumes/{uuid}', 'patch',
                          body={'qos.policy.name': qos_policy_group_name})
            ])
        else:
            self.client.send_request.assert_called_once_with(
                '/storage/volumes', 'post', body=body)
            self.assertFalse(self.client.volume_clone_split_start.called)

    @ddt.data(True, False)
    def test_create_volume_split(self, split):
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, 'volume_clone_split_start')
        self.mock_object(
            self.client.connection, 'get_vserver',
            mock.Mock(return_value='fake_svm'))
        body = {
            'name': fake.SHARE_NAME,
            'clone.parent_volume.name': fake.PARENT_SHARE_NAME,
            'clone.parent_snapshot.name': fake.PARENT_SNAPSHOT_NAME,
            'nas.path': '/%s' % fake.SHARE_NAME,
            'clone.is_flexclone': 'true',
            'svm.name': 'fake_svm',
        }

        self.client.create_volume_clone(
            fake.SHARE_NAME,
            fake.PARENT_SHARE_NAME,
            fake.PARENT_SNAPSHOT_NAME,
            split=split)

        self.assertFalse(self.client.volume_clone_split_start.called)

        self.client.send_request.assert_called_once_with(
            '/storage/volumes', 'post', body=body)

    def test_quiesce_snapmirror_vol(self):
        mock__quiesce_snapmirror = self.mock_object(
            self.client, '_quiesce_snapmirror')

        self.client.quiesce_snapmirror_vol(fake.SM_SOURCE_VSERVER,
                                           fake.SM_SOURCE_VOLUME,
                                           fake.SM_DEST_VSERVER,
                                           fake.SM_DEST_VOLUME)

        mock__quiesce_snapmirror.assert_called_once_with(
            source_vserver=fake.SM_SOURCE_VSERVER,
            source_volume=fake.SM_SOURCE_VOLUME,
            dest_vserver=fake.SM_DEST_VSERVER,
            dest_volume=fake.SM_DEST_VOLUME)

    def test__quiesce_snapmirror(self):
        fake_snapmirror = fake.REST_GET_SNAPMIRRORS_RESPONSE
        fake_uuid = fake_snapmirror[0]['uuid']
        fake_body = {'state': 'paused'}

        self.mock_object(self.client, 'send_request')

        mock_get_snap = self.mock_object(
            self.client, '_get_snapmirrors',
            mock.Mock(return_value=fake_snapmirror))

        self.client._quiesce_snapmirror()

        mock_get_snap.assert_called_once()
        self.client.send_request.assert_called_once_with(
            f'/snapmirror/relationships/{fake_uuid}', 'patch', body=fake_body)

    def test_break_snapmirror_vol(self):

        self.mock_object(self.client, '_break_snapmirror')

        self.client.break_snapmirror_vol(source_vserver=fake.SM_SOURCE_VSERVER,
                                         source_volume=fake.SM_SOURCE_VOLUME,
                                         dest_vserver=fake.SM_DEST_VSERVER,
                                         dest_volume=fake.SM_DEST_VOLUME)

        self.client._break_snapmirror.assert_called_once_with(
            source_vserver=fake.SM_SOURCE_VSERVER,
            source_volume=fake.SM_SOURCE_VOLUME,
            dest_vserver=fake.SM_DEST_VSERVER,
            dest_volume=fake.SM_DEST_VOLUME)

    def test__break_snapmirror(self):
        fake_snapmirror = fake.REST_GET_SNAPMIRRORS_RESPONSE
        fake_uuid = fake_snapmirror[0]['uuid']
        fake_body = {'state': 'broken_off'}

        self.mock_object(self.client, 'send_request')

        mock_get_snap = self.mock_object(
            self.client, '_get_snapmirrors',
            mock.Mock(return_value=fake_snapmirror))

        self.client._break_snapmirror()

        mock_get_snap.assert_called_once()
        self.client.send_request.assert_called_once_with(
            f'/snapmirror/relationships/{fake_uuid}', 'patch', body=fake_body)

    def test_resume_snapmirror_vol(self):
        mock = self.mock_object(self.client, '_resume_snapmirror')
        self.client.resume_snapmirror_vol(fake.SM_SOURCE_VSERVER,
                                          fake.SM_SOURCE_VOLUME,
                                          fake.SM_DEST_VSERVER,
                                          fake.SM_DEST_VOLUME)
        mock.assert_called_once_with(
            source_vserver=fake.SM_SOURCE_VSERVER,
            dest_vserver=fake.SM_DEST_VSERVER,
            source_volume=fake.SM_SOURCE_VOLUME,
            dest_volume=fake.SM_DEST_VOLUME)

    def test_resync_snapmirror_vol(self):
        mock = self.mock_object(self.client, '_resync_snapmirror')
        self.client.resync_snapmirror_vol(fake.SM_SOURCE_VSERVER,
                                          fake.SM_SOURCE_VOLUME,
                                          fake.SM_DEST_VSERVER,
                                          fake.SM_DEST_VOLUME)
        mock.assert_called_once_with(
            source_vserver=fake.SM_SOURCE_VSERVER,
            dest_vserver=fake.SM_DEST_VSERVER,
            source_volume=fake.SM_SOURCE_VOLUME,
            dest_volume=fake.SM_DEST_VOLUME)

    @ddt.data('async', 'sync')
    def test__resume_snapmirror(self, snapmirror_policy):
        api_response = copy.deepcopy(fake.REST_GET_SNAPMIRRORS_RESPONSE)
        api_response[0]['policy-type'] = snapmirror_policy
        mock_snapmirror = self.mock_object(
            self.client, '_get_snapmirrors',
            mock.Mock(return_value=api_response))
        mock_request = self.mock_object(self.client, 'send_request')

        snapmirror_uuid = fake.FAKE_UUID

        body_resync = {}
        if snapmirror_policy == 'async':
            body_resync['state'] = 'snapmirrored'
        elif snapmirror_policy == 'sync':
            body_resync['state'] = 'in_sync'

        self.client._resume_snapmirror(fake.SM_SOURCE_PATH, fake.SM_DEST_PATH)

        mock_request.assert_called_once_with('/snapmirror/relationships/' +
                                             snapmirror_uuid, 'patch',
                                             body=body_resync,
                                             wait_on_accepted=False)

        mock_snapmirror.assert_called_once_with(
            source_path=fake.SM_SOURCE_PATH,
            dest_path=fake.SM_DEST_PATH,
            source_vserver=None,
            source_volume=None,
            dest_vserver=None,
            dest_volume=None,
            enable_tunneling=None,
            list_destinations_only=None)

    def test__resync_snapmirror(self):
        mock = self.mock_object(self.client, '_resume_snapmirror')
        self.client._resume_snapmirror(fake.SM_SOURCE_PATH,
                                       fake.SM_DEST_PATH)
        mock.assert_called_once_with(fake.SM_SOURCE_PATH, fake.SM_DEST_PATH)

    def test_add_nfs_export_rule(self):

        mock_get_nfs_export_rule_indices = self.mock_object(
            self.client, '_get_nfs_export_rule_indices',
            mock.Mock(return_value=[]))
        mock_add_nfs_export_rule = self.mock_object(
            self.client, '_add_nfs_export_rule')
        mock_update_nfs_export_rule = self.mock_object(
            self.client, '_update_nfs_export_rule')
        auth_methods = ['sys']

        self.client.add_nfs_export_rule(fake.EXPORT_POLICY_NAME,
                                        fake.IP_ADDRESS,
                                        False,
                                        auth_methods)

        mock_get_nfs_export_rule_indices.assert_called_once_with(
            fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS)
        mock_add_nfs_export_rule.assert_called_once_with(
            fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False,
            auth_methods, anon_user_id=None)
        self.assertFalse(mock_update_nfs_export_rule.called)

    def test_set_qos_policy_group_for_volume(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        mock_get_volume = self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value=volume))

        mock_send_request = self.mock_object(
            self.client, 'send_request')

        self.client.set_qos_policy_group_for_volume(
            volume['name'], fake.QOS_POLICY_GROUP_NAME)

        mock_get_volume.assert_called_once_with(vol_name=volume['name'])

        body = {'qos.policy.name': fake.QOS_POLICY_GROUP_NAME}
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{volume["uuid"]}', 'patch', body=body)

    def test__update_snapmirror(self):
        api_response = copy.deepcopy(fake.REST_GET_SNAPMIRRORS_RESPONSE)
        mock_snapmirror = self.mock_object(
            self.client, '_get_snapmirrors',
            mock.Mock(return_value=api_response))
        mock_sr = self.mock_object(self.client, 'send_request')
        self.client._update_snapmirror(fake.SM_SOURCE_PATH,
                                       fake.SM_DEST_PATH,
                                       fake.SM_SOURCE_VSERVER,
                                       fake.SM_DEST_VSERVER,
                                       fake.SM_SOURCE_VOLUME,
                                       fake.SM_DEST_VOLUME)
        mock_sr.assert_called_once()
        mock_snapmirror.assert_called_once_with(
            source_path=fake.SM_SOURCE_PATH,
            dest_path=fake.SM_DEST_PATH,
            source_vserver=fake.SM_SOURCE_VSERVER,
            source_volume=fake.SM_SOURCE_VOLUME,
            dest_vserver=fake.SM_DEST_VSERVER,
            dest_volume=fake.SM_DEST_VOLUME,
            enable_tunneling=None,
            list_destinations_only=None)

    def test_get_cluster_name(self):
        """Get all available cluster nodes."""

        return_value = fake.FAKE_GET_CLUSTER_NODE_VERSION_REST

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))
        test_result = self.client.get_cluster_name()

        self.client.send_request.assert_called_once_with(
            '/cluster', 'get', enable_tunneling=False
        )

        expected_result = return_value.get('name')

        self.assertEqual(test_result, expected_result)

    @ddt.data(True, False)
    def test_check_volume_clone_split_completed(self, clone):
        mock__get_volume_by_args = self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value={'clone': {'is_flexclone': clone}}))

        res = self.client.check_volume_clone_split_completed(
            fake.VOLUME_NAMES[0])

        mock__get_volume_by_args.assert_called_once_with(
            vol_name=fake.VOLUME_NAMES[0], fields='clone.is_flexclone')
        self.assertEqual(not clone, res)

    def test_rehost_volume(self):
        self.mock_object(self.client, 'send_request')
        self.client.rehost_volume("fake_vol", "fake_svm", "fake_svm_2")
        body = {
            "vserver": "fake_svm",
            "volume": "fake_vol",
            "destination_vserver": "fake_svm_2"
        }
        self.client.send_request.assert_called_once_with(
            "/private/cli/volume/rehost", 'post', body=body)

    def test_get_net_options(self):

        res = self.client.get_net_options()

        self.assertTrue(res['ipv6-enabled'])

    def test_set_qos_adaptive_policy_group_for_volume(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        mock_get_volume = self.mock_object(
            self.client, '_get_volume_by_args',
            mock.Mock(return_value=volume))

        mock_send_request = self.mock_object(
            self.client, 'send_request')

        self.client.set_qos_adaptive_policy_group_for_volume(
            volume['name'], fake.QOS_POLICY_GROUP_NAME)

        mock_get_volume.assert_called_once_with(vol_name=volume['name'])

        body = {'qos.policy.name': fake.QOS_POLICY_GROUP_NAME}
        mock_send_request.assert_called_once_with(
            f'/storage/volumes/{volume["uuid"]}', 'patch', body=body)

    def test__list_vservers(self):
        api_response = fake.VSERVER_DATA_LIST_RESPONSE_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))
        result = self.client._list_vservers()
        query = {
            'fields': 'name',
        }
        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get', query=query,
                      enable_tunneling=False)])
        self.assertListEqual(
            [fake.VSERVER_NAME, fake.VSERVER_NAME_2], result)

    def test_list_vservers_not_found(self):
        api_response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))
        result = self.client._list_vservers()
        self.assertListEqual([], result)

    def test_get_ems_log_destination_vserver(self):
        mock_list_vservers = self.mock_object(
            self.client,
            '_list_vservers',
            mock.Mock(return_value=[fake.VSERVER_NAME]))
        result = self.client._get_ems_log_destination_vserver()
        mock_list_vservers.assert_called_once_with()
        self.assertEqual(fake.VSERVER_NAME, result)

    def test_get_ems_log_destination_vserver_not_found(self):
        mock_list_vservers = self.mock_object(
            self.client,
            '_list_vservers',
            mock.Mock(return_value=[]))

        self.assertRaises(exception.NotFound,
                          self.client._get_ems_log_destination_vserver)

        mock_list_vservers.assert_called_once_with()

    def test_send_ems_log_message(self):

        message_dict = {
            'computer-name': '25-dev-vm',
            'event-source': 'Cinder driver NetApp_iSCSI_Cluster_direct',
            'app-version': '20.1.0.dev|vendor|Linux-5.4.0-120-generic-x86_64',
            'category': 'provisioning',
            'log-level': '5',
            'auto-support': 'false',
            'event-id': '1',
            'event-description':
                '{"pools": {"vserver": "vserver_name",'
                + '"aggregates": [], "flexvols": ["flexvol_01"]}}'
        }

        body = {
            'computer_name': message_dict['computer-name'],
            'event_source': message_dict['event-source'],
            'app_version': message_dict['app-version'],
            'category': message_dict['category'],
            'severity': 'notice',
            'autosupport_required': message_dict['auto-support'] == 'true',
            'event_id': message_dict['event-id'],
            'event_description': message_dict['event-description'],
        }

        self.mock_object(self.client, '_get_ems_log_destination_vserver',
                         mock.Mock(return_value='vserver_name'))
        self.mock_object(self.client, 'send_request')

        self.client.send_ems_log_message(message_dict)

        self.client.send_request.assert_called_once_with(
            '/support/ems/application-logs', 'post', body=body)

    @ddt.data('cp_phase_times', 'domain_busy')
    def test_get_performance_counter_info(self, counter_name):

        response1 = fake.PERF_COUNTER_LIST_INFO_WAFL_RESPONSE_REST
        response2 = fake.PERF_COUNTER_TABLE_ROWS_WAFL

        object_name = 'wafl'

        mock_send_request = self.mock_object(
            self.client, 'send_request',
            mock.Mock(side_effect=[response1, response2]))

        result = self.client.get_performance_counter_info(object_name,
                                                          counter_name)

        expected = {
            'name': 'cp_phase_times',
            'base-counter': 'total_cp_msecs',
            'labels': fake.PERF_COUNTER_TOTAL_CP_MSECS_LABELS_RESULT,
        }

        query1 = {
            'counter_schemas.name': counter_name,
            'fields': 'counter_schemas.*'
        }

        query2 = {
            'counters.name': counter_name,
            'fields': 'counters.*'
        }

        if counter_name == 'domain_busy':
            expected['name'] = 'domain_busy'
            expected['labels'] = (
                fake.PERF_COUNTER_TOTAL_CP_MSECS_LABELS_REST)
            query1['counter_schemas.name'] = 'domain_busy_percent'
            query2['counters.name'] = 'domain_busy_percent'

        self.assertEqual(expected, result)

        mock_send_request.assert_has_calls([
            mock.call(f'/cluster/counter/tables/{object_name}',
                      'get', query=query1),
            mock.call(f'/cluster/counter/tables/{object_name}/rows',
                      'get', query=query2, enable_tunneling=False),
        ])

    def test_get_performance_counter_info_not_found_rows(self):
        response1 = fake.PERF_COUNTER_LIST_INFO_WAFL_RESPONSE_REST
        response2 = fake.NO_RECORDS_RESPONSE_REST

        object_name = 'wafl'
        counter_name = 'cp_phase_times'

        self.mock_object(
            self.client, 'send_request',
            mock.Mock(side_effect=[response1, response2]))

        result = self.client.get_performance_counter_info(object_name,
                                                          counter_name)

        expected = {
            'name': 'cp_phase_times',
            'base-counter': 'total_cp_msecs',
            'labels': [],
        }
        self.assertEqual(expected, result)

    def test_get_performance_instance_uuids(self):
        response = fake.PERF_COUNTER_TABLE_ROWS_WAFL

        mock_send_request = self.mock_object(
            self.client, 'send_request',
            mock.Mock(return_value=response))

        object_name = 'wafl'
        result = self.client.get_performance_instance_uuids(
            object_name, fake.NODE_NAME)

        expected = [fake.NODE_NAME + ':wafl']
        self.assertEqual(expected, result)

        query = {
            'id': fake.NODE_NAME + ':*',
        }
        mock_send_request.assert_called_once_with(
            f'/cluster/counter/tables/{object_name}/rows',
            'get', query=query, enable_tunneling=False)

    def test_get_performance_counters(self):
        response = fake.PERF_GET_INSTANCES_PROCESSOR_RESPONSE_REST

        mock_send_request = self.mock_object(
            self.client, 'send_request',
            mock.Mock(return_value=response))

        instance_uuids = [
            fake.NODE_NAME + ':processor0',
            fake.NODE_NAME + ':processor1',
        ]
        object_name = 'processor'
        counter_names = ['domain_busy', 'processor_elapsed_time']
        rest_counter_names = ['domain_busy_percent', 'elapsed_time']
        result = self.client.get_performance_counters(object_name,
                                                      instance_uuids,
                                                      counter_names)

        expected = fake.PERF_COUNTERS_PROCESSOR_EXPECTED
        self.assertEqual(expected, result)

        query = {
            'id': '|'.join(instance_uuids),
            'counters.name': '|'.join(rest_counter_names),
            'fields': 'id,counter_table.name,counters.*',
        }

        mock_send_request.assert_called_once_with(
            f'/cluster/counter/tables/{object_name}/rows',
            'get', query=query)

    def test__get_deleted_nfs_export_policies(self):

        api_response = fake.DELETED_EXPORT_POLICY_GET_ITER_RESPONSE_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))

        result = self.client._get_deleted_nfs_export_policies()

        query = {
            'name': 'deleted_manila_*',
            'fields': 'name,svm.name',
        }

        self.assertSequenceEqual(fake.DELETED_EXPORT_POLICIES, result)
        self.client.send_request.assert_has_calls([
            mock.call('/protocols/nfs/export-policies',
                      'get', query=query)])

    def test_prune_deleted_nfs_export_policies(self):
        self.mock_object(self.client, '_get_deleted_nfs_export_policies',
                         mock.Mock(return_value=fake.DELETED_EXPORT_POLICIES))
        self.mock_object(self.client, 'delete_nfs_export_policy')

        self.client.prune_deleted_nfs_export_policies()

        self.assertTrue(self.client.delete_nfs_export_policy.called)

        self.client.delete_nfs_export_policy.assert_has_calls([
            mock.call(fake.DELETED_EXPORT_POLICIES[fake.VSERVER_NAME][0]),
            mock.call(fake.DELETED_EXPORT_POLICIES[fake.VSERVER_NAME][1]),
            mock.call(fake.DELETED_EXPORT_POLICIES[fake.VSERVER_NAME_2][0]),
        ])

    def test_prune_deleted_nfs_export_policies_api_error(self):
        self.mock_object(self.client,
                         '_get_deleted_nfs_export_policies',
                         mock.Mock(return_value=fake.DELETED_EXPORT_POLICIES))
        self.mock_object(self.client,
                         'delete_nfs_export_policy',
                         self._mock_api_error())

        self.client.prune_deleted_nfs_export_policies()

    def test__get_security_key_manager_nve_support_enabled(self):
        api_response = fake.SECUTITY_KEY_MANAGER_SUPPORT_RESPONSE_TRUE_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))

        result = self.client._get_security_key_manager_nve_support()

        self.assertTrue(result)

        query = {'fields': 'volume_encryption.*'}
        self.client.send_request.assert_has_calls([
            mock.call('/security/key-managers', 'get', query=query)])

    def test__get_security_key_manager_nve_support_disabled(self):
        api_response = fake.SECUTITY_KEY_MANAGER_SUPPORT_RESPONSE_FALSE_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))

        result = self.client._get_security_key_manager_nve_support()

        self.assertFalse(result)

        query = {'fields': 'volume_encryption.*'}
        self.client.send_request.assert_has_calls([
            mock.call('/security/key-managers', 'get', query=query)])

    def test__get_security_key_manager_nve_support_no_records(self):
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=fake.NO_RECORDS_RESPONSE_REST))

        result = self.client._get_security_key_manager_nve_support()

        self.assertFalse(result)

        query = {'fields': 'volume_encryption.*'}
        self.client.send_request.assert_has_calls([
            mock.call('/security/key-managers', 'get', query=query)])

    def test__get_security_key_manager_nve_support_no_license(self):
        self.mock_object(self.client,
                         'send_request',
                         self._mock_api_error())

        result = self.client._get_security_key_manager_nve_support()

        self.assertFalse(result)

        query = {'fields': 'volume_encryption.*'}
        self.client.send_request.assert_has_calls([
            mock.call('/security/key-managers', 'get', query=query)])

    def test_get_nfs_config_default(self):
        api_response = fake.NFS_CONFIG_DEFAULT_RESULT_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))

        result = self.client.get_nfs_config_default(['tcp-max-xfer-size',
                                                     'udp-max-xfer-size'])
        expected = {
            'tcp-max-xfer-size': '65536',
            'udp-max-xfer-size': '32768',
        }
        self.assertEqual(expected, result)

        query = {'fields': 'transport.*'}
        self.client.send_request.assert_called_once_with(
            '/protocols/nfs/services/', 'get', query=query)

    def test_get_kerberos_service_principal_name(self):

        spn = self.client._get_kerberos_service_principal_name(
            fake.KERBEROS_SECURITY_SERVICE, fake.VSERVER_NAME
        )
        self.assertEqual(fake.KERBEROS_SERVICE_PRINCIPAL_NAME, spn)

    def test_get_cifs_server_name(self):

        expected_return = 'FAKE-VSE-SERVER'

        cifs_server = self.client._get_cifs_server_name(fake.VSERVER_NAME)

        self.assertEqual(expected_return, cifs_server)

    def test_list_network_interfaces(self):

        api_response = fake.GENERIC_NETWORK_INTERFACES_GET_REPONSE
        expected_result = [fake.LIF_NAME]

        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))

        fake_query = {
            'fields': 'name'
        }

        result = self.client.list_network_interfaces()

        self.client.send_request.assert_has_calls([
            mock.call('/network/ip/interfaces', 'get', query=fake_query)])
        self.assertEqual(expected_result, result)

    def test_create_kerberos_realm(self):

        fake_security = fake.KERBEROS_SECURITY_SERVICE

        fake_body = {
            'comment': '',
            'kdc.ip': fake_security['server'],
            'kdc.port': '88',
            'kdc.vendor': 'other',
            'name': fake_security['domain'].upper(),
        }

        self.mock_object(self.client, 'send_request')

        self.client.create_kerberos_realm(fake.KERBEROS_SECURITY_SERVICE)

        self.client.send_request.assert_called_once_with(
            '/protocols/nfs/kerberos/realms', 'post', body=fake_body)

    def test_configure_kerberos(self):

        fake_api_response = fake.NFS_LIFS_REST
        fake_security = fake.KERBEROS_SECURITY_SERVICE
        fake_keberos_name = fake.KERBEROS_SERVICE_PRINCIPAL_NAME

        fake_body = {
            'password': fake_security['password'],
            'user': fake_security['user'],
            'interface.name': fake.LIF_NAME,
            'enabled': True,
            'spn': fake_keberos_name
        }

        self.mock_object(self.client, 'configure_dns')
        self_get_kerberos = self.mock_object(
            self.client, '_get_kerberos_service_principal_name',
            mock.Mock(return_value=fake_keberos_name))
        self.mock_object(self.client, 'get_network_interfaces',
                         mock.Mock(return_value=fake_api_response))
        self.mock_object(self.client, 'send_request')

        self.client.configure_kerberos(fake.KERBEROS_SECURITY_SERVICE,
                                       fake.VSERVER_NAME)

        self.client.configure_dns.assert_called_once_with(
            fake.KERBEROS_SECURITY_SERVICE, vserver_name=fake.VSERVER_NAME)
        self_get_kerberos.assert_called_once_with(
            fake.KERBEROS_SECURITY_SERVICE, fake.VSERVER_NAME)
        self.client.get_network_interfaces.assert_called_once_with()
        self.client.send_request.assert_has_calls([
            mock.call('/protocols/nfs/kerberos/interfaces/fake_uuid_1',
                      'patch', body=fake_body),
            mock.call('/protocols/nfs/kerberos/interfaces/fake_uuid_2',
                      'patch', body=fake_body),
            mock.call('/protocols/nfs/kerberos/interfaces/fake_uuid_3',
                      'patch', body=fake_body)
        ])

    @ddt.data(
        {'security_service': fake.CIFS_SECURITY_SERVICE,
            'aes_encryption': False, 'smb_signing': False},
        {'security_service': fake.CIFS_SECURITY_SERVICE,
            'aes_encryption': True, 'smb_signing': False},
        {'security_service': fake.CIFS_SECURITY_SERVICE_3,
            'aes_encryption': False, 'smb_signing': True},
        {'security_service': fake.CIFS_SECURITY_SERVICE_3,
            'aes_encryption': True, 'smb_signing': True}
    )
    @ddt.unpack
    def test_configure_active_directory(self, security_service,
                                        aes_encryption, smb_signing):

        fake_security = copy.deepcopy(security_service)

        fake_body1 = {
            'ad_domain.user': fake_security['user'],
            'ad_domain.password': fake_security['password'],
            'force': 'true',
            'name': 'FAKE-VSE-SERVER',
            'ad_domain.fqdn': fake_security['domain'],
        }

        self.mock_object(self.client, 'configure_dns')
        self.mock_object(self.client, 'set_preferred_dc')
        self.mock_object(self.client, 'configure_cifs_aes_encryption')
        self.mock_object(self.client, 'configure_cifs_signing')
        self.mock_object(self.client, 'wait_for_cifs_server')
        self.mock_object(self.client, '_get_cifs_server_name',
                         mock.Mock(return_value='FAKE-VSE-SERVER'))
        self.mock_object(self.client, 'send_request')

        self.client.configure_active_directory(fake_security,
                                               fake.VSERVER_NAME,
                                               aes_encryption,
                                               smb_signing)

        self.client.configure_dns.assert_called_once_with(
            fake_security, vserver_name=fake.VSERVER_NAME)
        self.client.set_preferred_dc.assert_called_once_with(
            fake_security, fake.VSERVER_NAME)
        self.client.configure_cifs_aes_encryption.assert_called_once_with(
            fake.VSERVER_NAME, aes_encryption)
        if smb_signing:
            self.client.configure_cifs_signing.assert_called_once()
        else:
            self.client.configure_cifs_signing.assert_not_called()
        self.client._get_cifs_server_name.assert_called_once_with(
            fake.VSERVER_NAME)

        if fake_security['ou'] is not None:
            fake_body1['ad_domain.organizational_unit'] = fake_security['ou']
            fake_body2 = fake_body1

            self.client.send_request.assert_called_once_with(
                '/protocols/cifs/services', 'post', body=fake_body2)
        else:
            self.client.send_request.assert_called_once_with(
                '/protocols/cifs/services', 'post', body=fake_body1)

    def test__create_ldap_client_ad(self):
        mock_dns = self.mock_object(self.client, 'configure_dns')
        mock_sr = self.mock_object(self.client, 'send_request')
        security_service = {
            'domain': 'fake_domain',
            'user': 'fake_user',
            'ou': 'fake_ou',
            'dns_ip': 'fake_ip',
            'password': 'fake_password'
        }

        ad_domain = security_service.get('domain')
        body = {
            'port': '389',
            'schema': 'MS-AD-BIS',
            'bind_dn': (security_service.get('user') + '@' + ad_domain),
            'bind_password': security_service.get('password'),
            'svm.name': fake.VSERVER_NAME,
            'base_dn': security_service.get('ou'),
            'ad_domain': security_service.get('domain'),
        }

        self.client._create_ldap_client(security_service,
                                        vserver_name=fake.VSERVER_NAME)
        mock_dns.assert_called_once_with(security_service)
        mock_sr.assert_called_once_with('/name-services/ldap', 'post',
                                        body=body)

    def test__create_ldap_client_linux(self):
        mock_dns = self.mock_object(self.client, 'configure_dns')
        mock_sr = self.mock_object(self.client, 'send_request')
        security_service = {
            'server': 'fake_server',
            'user': 'fake_user',
            'ou': 'fake_ou',
            'dns_ip': 'fake_ip'
        }

        body = {
            'port': '389',
            'schema': 'RFC-2307',
            'bind_dn': security_service.get('user'),
            'bind_password': security_service.get('password'),
            'svm.name': fake.VSERVER_NAME,
            'base_dn': security_service.get('ou'),
            'servers': [security_service.get('server')]
        }

        self.client._create_ldap_client(security_service,
                                        vserver_name=fake.VSERVER_NAME)
        mock_dns.assert_called_once_with(security_service)
        mock_sr.assert_called_once_with('/name-services/ldap', 'post',
                                        body=body)

    def test_configure_dns_already_present(self):
        dns_config = {
            'domains': [fake.KERBEROS_SECURITY_SERVICE['domain']],
            'dns-ips': [fake.KERBEROS_SECURITY_SERVICE['dns_ip']],
        }
        self.mock_object(self.client, 'get_dns_config',
                         mock.Mock(return_value=dns_config))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake.FAKE_VOL_MOVE_STATUS))

        security_service = copy.deepcopy(fake.KERBEROS_SECURITY_SERVICE)
        self.client.configure_dns(security_service)

        net_dns_create_args = {
            'domains': [security_service['domain']],
            'servers': [security_service['dns_ip']],
        }

        uuid = fake.FAKE_VOL_MOVE_STATUS['records'][0]['uuid']
        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get',
                      query={'name': None, 'fields': 'uuid'}),
            mock.call(f'/name-services/dns/{uuid}', 'patch',
                      body=net_dns_create_args)])

    def test_configure_dns_for_active_directory(self):

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake.FAKE_VOL_MOVE_STATUS))
        self.mock_object(self.client, 'get_dns_config',
                         mock.Mock(return_value={}))

        security_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
        self.client.configure_dns(security_service)

        net_dns_create_args = {
            'domains': [security_service['domain']],
            'servers': [security_service['dns_ip']],
        }

        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get',
                      query={'name': None, 'fields': 'uuid'}),
            mock.call('/name-services/dns', 'post', body=net_dns_create_args)])

    def test_configure_dns_multiple_dns_ip(self):

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake.FAKE_VOL_MOVE_STATUS))
        self.mock_object(self.client, 'get_dns_config',
                         mock.Mock(return_value={}))
        mock_dns_ips = '10.0.0.5, 10.0.0.6, 10.0.0.7'
        security_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
        security_service['dns_ip'] = mock_dns_ips

        args_dns = {'domains': [security_service['domain']],
                    'servers': ['10.0.0.5',
                                '10.0.0.6',
                                '10.0.0.7']}
        self.client.configure_dns(security_service)

        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get',
                      query={'name': None, 'fields': 'uuid'}),
            mock.call('/name-services/dns', 'post', body=args_dns)])

    def test_configure_dns_for_kerberos(self):

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake.FAKE_VOL_MOVE_STATUS))
        self.mock_object(self.client, 'get_dns_config',
                         mock.Mock(return_value={}))

        security_service = copy.deepcopy(fake.KERBEROS_SECURITY_SERVICE)
        self.client.configure_dns(security_service)

        net_dns_create_args = {
            'domains': [security_service['domain']],
            'servers': [security_service['dns_ip']],
        }

        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get',
                      query={'name': None, 'fields': 'uuid'}),
            mock.call('/name-services/dns', 'post', body=net_dns_create_args)])

    def test_configure_dns_api_error(self):
        self.mock_object(self.client, 'send_request', self._mock_api_error())
        self.mock_object(self.client, 'get_dns_config',
                         mock.Mock(return_value={}))
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value={}))

        self.assertRaises(exception.NetAppException,
                          self.client.configure_dns,
                          copy.deepcopy(fake.KERBEROS_SECURITY_SERVICE))

    def test_get_dns_config_no_response(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=netapp_api.api.NaApiError))
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value={}))
        self.assertRaises(exception.NetAppException,
                          self.client.get_dns_config)

    def test_get_dns_config(self):
        api_response = fake.DNS_REST_RESPONSE
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=api_response))
        fake_uuid = fake.FAKE_VOL_MOVE_STATUS['records'][0]['svm']['uuid']
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake_uuid))

        result = self.client.get_dns_config()

        expected_result = {
            'dns-state': 'true',
            'domains': ['example.com', 'example2.example3.com'],
            'dns-ips': ['10.224.65.20', '2001:db08:a0b:12f0::1']
        }
        self.assertEqual(expected_result, result)
        self.client.send_request.assert_called_once_with(
            f'/name-services/dns/{fake_uuid}', 'get')

    @ddt.data(fake.LDAP_AD_SECURITY_SERVICE, fake.CIFS_SECURITY_SERVICE_3,
              fake.KERBEROS_SECURITY_SERVICE)
    def test_setup_security_services(self, security_service):
        fake_response = fake.FAKE_GET_CLUSTER_NODE_VERSION_REST
        mock_request = self.mock_object(self.client, 'send_request',
                                        mock.Mock(return_value=fake_response))
        self.mock_object(self.client, 'configure_ldap')
        self.mock_object(self.client, 'configure_active_directory')
        self.mock_object(self.client, 'configure_cifs_options')
        self.mock_object(self.client, 'create_kerberos_realm')
        self.mock_object(self.client, 'configure_kerberos')

        ss_copy = copy.deepcopy(security_service)
        self.client.setup_security_services([ss_copy], self.client,
                                            'fake_vservername', False, False)
        uuid = fake_response.get('records')[0].get('uuid')
        body = {
            'nsswitch.namemap': ['ldap', 'files'],
            'nsswitch.group': ['ldap', 'files'],
            'nsswitch.netgroup': ['ldap', 'files'],
            'nsswitch.passwd': ['ldap', 'files'],
        }
        mock_request.assert_has_calls([
            mock.call('/svm/svms', 'get',
                      query={'name': 'fake_vservername', 'fields': 'uuid'}),
            mock.call(f'/svm/svms/{uuid}', 'patch', body=body)])

    def test_modify_ldap_ad(self):
        fake_svm_uuid = fake.FAKE_UUID
        mock_svm_uuid = self.mock_object(self.client,
                                         '_get_unique_svm_by_name',
                                         mock.Mock(return_value=fake_svm_uuid))
        mock_sr = self.mock_object(self.client, 'send_request')
        security_service = {
            'domain': 'fake_domain',
            'user': 'fake_user',
            'ou': 'fake_ou',
            'dns_ip': 'fake_ip',
            'password': 'fake_password'
        }

        ad_domain = security_service.get('domain')
        body = {
            'port': '389',
            'schema': 'MS-AD-BIS',
            'bind_dn': (security_service.get('user') + '@' + ad_domain),
            'bind_password': security_service.get('password'),
            'base_dn': security_service.get('ou'),
            'ad_domain': security_service.get('domain'),
        }

        self.client.modify_ldap(security_service, None)
        mock_svm_uuid.assert_called_once_with(None)
        mock_sr.assert_called_once_with(f'/name-services/ldap/{fake_svm_uuid}',
                                        'patch', body=body)

    def test_modify_ldap_linux(self):
        fake_svm_uuid = fake.FAKE_UUID
        mock_svm_uuid = self.mock_object(self.client,
                                         '_get_unique_svm_by_name',
                                         mock.Mock(return_value=fake_svm_uuid))
        mock_sr = self.mock_object(self.client, 'send_request')
        security_service = {
            'server': 'fake_server',
            'user': 'fake_user',
            'ou': 'fake_ou',
            'dns_ip': 'fake_ip'
        }

        body = {
            'port': '389',
            'schema': 'RFC-2307',
            'bind_dn': security_service.get('user'),
            'bind_password': security_service.get('password'),
            'base_dn': security_service.get('ou'),
            'servers': [security_service.get('server')]
        }

        self.client.modify_ldap(security_service, None)
        mock_svm_uuid.assert_called_once_with(None)
        mock_sr.assert_called_once_with(f'/name-services/ldap/{fake_svm_uuid}',
                                        'patch', body=body)

    def test_update_kerberos_realm(self):
        self.mock_object(self.client,
                         '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        fake_uuid = fake.FAKE_UUID
        self.mock_object(self.client, 'send_request')
        self.client.update_kerberos_realm(fake.KERBEROS_SECURITY_SERVICE)
        fake_domain = fake.KERBEROS_SECURITY_SERVICE['domain']
        body = {
            'kdc-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
        }

        self.client.send_request.assert_has_calls([
            mock.call(
                f'/protocols/nfs/kerberos/realms/{fake_uuid}/{fake_domain}',
                'patch', body=body)])

    def test__get_unique_svm_by_name(self):
        response = fake.SVMS_LIST_SIMPLE_RESPONSE_REST
        svm = fake.SVM_ITEM_SIMPLE_RESPONSE_REST['uuid']

        fake_query = {
            'name': fake.VSERVER_NAME,
            'fields': 'uuid'
        }

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))

        result = self.client._get_unique_svm_by_name(
            fake.VSERVER_NAME)

        self.client.send_request.assert_called_once_with(
            '/svm/svms', 'get', query=fake_query)

        self.assertEqual(svm, result)

    def test_update_dns_configuration(self):
        dns_config = {
            'domains': [fake.KERBEROS_SECURITY_SERVICE['domain']],
            'dns-ips': [fake.KERBEROS_SECURITY_SERVICE['dns_ip']],
        }

        body = {
            'domains': [fake.KERBEROS_SECURITY_SERVICE['domain']],
            'servers': [fake.KERBEROS_SECURITY_SERVICE['dns_ip']]
        }

        fake_uuid = 'fake_uuid'

        self.mock_object(self.client, 'get_dns_config',
                         mock.Mock(return_value=dns_config))

        self.mock_object(self.client,
                         '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake_uuid))

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake.FAKE_VOL_MOVE_STATUS))

        self.client.configure_dns(fake.KERBEROS_SECURITY_SERVICE)
        body = {
            'domains': [fake.KERBEROS_SECURITY_SERVICE['domain']],
            'servers': [fake.KERBEROS_SECURITY_SERVICE['dns_ip']]
        }

        self.client.send_request.assert_called_once_with(
            f'/name-services/dns/{fake_uuid}', 'patch', body=body)

    def test_remove_preferred_dcs(self):
        svm_uuid = copy.deepcopy(fake.FAKE_UUID)
        fqdn = copy.deepcopy(fake.PREFERRED_DC_REST.get('fqdn'))
        server_ip = copy.deepcopy(fake.PREFERRED_DC_REST.get('server_ip'))
        fake_response = copy.deepcopy(fake.PREFERRED_DC_REST)
        fake_ss = copy.deepcopy(fake.LDAP_AD_SECURITY_SERVICE)
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake_response))
        self.client.remove_preferred_dcs(fake_ss, svm_uuid)
        query = {
            'fqdn': fake.LDAP_AD_SECURITY_SERVICE.get('domain'),
        }
        self.client.send_request.assert_has_calls([
            mock.call(f'/protocols/cifs/domains/{svm_uuid}/'
                      f'preferred-domain-controllers/', 'get'),
            mock.call(f'/protocols/cifs/domains/{svm_uuid}/'
                      f'preferred-domain-controllers/{fqdn}/{server_ip}',
                      'delete', query=query)
        ])

    def test_remove_preferred_dcs_api_error(self):
        fake_response = copy.deepcopy(fake.PREFERRED_DC_REST)
        fake_ss = copy.deepcopy(fake.LDAP_AD_SECURITY_SERVICE)
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake_response))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=netapp_api.api.NaApiError))
        self.assertRaises(netapp_api.api.NaApiError,
                          self.client.remove_preferred_dcs,
                          fake_ss, fake.FAKE_UUID)

    def test_configure_cifs_signing(self):
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))

        self.client.configure_cifs_signing(fake.VSERVER_NAME)
        self.client._get_unique_svm_by_name.assert_called_once_with(
            fake.VSERVER_NAME)

        body = {
            'security.smb_signing': True,
        }
        self.client.send_request.assert_called_once_with(
            f'/protocols/cifs/services/{fake.FAKE_UUID}',
            'patch', body=body)

    def test_configure_cifs_aes_encryption_enable(self):
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))

        self.client.configure_cifs_aes_encryption(fake.VSERVER_NAME, True)
        self.client._get_unique_svm_by_name.assert_called_once_with(
            fake.VSERVER_NAME)

        body = {
            'security.advertised_kdc_encryptions': ['aes-128', 'aes-256'],
        }
        self.client.send_request.assert_called_once_with(
            f'/protocols/cifs/services/{fake.FAKE_UUID}',
            'patch', body=body)

    def test_configure_cifs_aes_encryption_disable(self):
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))

        self.client.configure_cifs_aes_encryption(fake.VSERVER_NAME, False)
        self.client._get_unique_svm_by_name.assert_called_once_with(
            fake.VSERVER_NAME)

        body = {
            'security.advertised_kdc_encryptions': ['des', 'rc4'],
        }
        self.client.send_request.assert_called_once_with(
            f'/protocols/cifs/services/{fake.FAKE_UUID}',
            'patch', body=body)

    def test_set_preferred_dc(self):
        fake_ss = copy.deepcopy(fake.LDAP_AD_SECURITY_SERVICE_WITH_SERVER)
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))

        self.client.set_preferred_dc(fake_ss, fake.VSERVER_NAME)

        self.client._get_unique_svm_by_name.assert_called_once_with(
            fake.VSERVER_NAME)

        query = {
            'fqdn': fake_ss['domain'],
            'skip_config_validation': 'false',
            'server_ip': ['10.10.10.1']
        }
        self.client.send_request.assert_called_once_with(
            f'/protocols/cifs/domains/{fake.FAKE_UUID}'
            '/preferred-domain-controllers', 'post', query=query)

    @ddt.data(None, 'cluster_name')
    def test_create_vserver_peer(self, cluster_name):

        self.mock_object(self.client, 'send_request')

        self.client.create_vserver_peer(fake.VSERVER_NAME,
                                        fake.VSERVER_PEER_NAME,
                                        peer_cluster_name=cluster_name)

        body = {
            'svm.name': fake.VSERVER_NAME,
            'peer.svm.name': fake.VSERVER_PEER_NAME,
            'applications': ['snapmirror'],
        }
        if cluster_name:
            body['peer.cluster.name'] = cluster_name

        self.client.send_request.assert_has_calls([
            mock.call('/svm/peers', 'post', body=body,
                      enable_tunneling=False)])

    def test__get_svm_peer_uuid(self):
        response = {
            "records": [{
                "uuid": "fake-vserver-uuid",
                "name": fake.VSERVER_NAME,
                "svm": {
                    "name": fake.VSERVER_NAME,
                },
                "peer": {
                    "svm": {
                        "name": fake.VSERVER_PEER_NAME,
                    }
                }
            }],
        }
        expected_result = "fake-vserver-uuid"
        return_value = response['records'][0]['uuid']
        self.mock_object(self.client, '_get_svm_peer_uuid',
                         mock.Mock(return_value=return_value))

        result = self.client._get_svm_peer_uuid(
            fake.VSERVER_NAME, fake.VSERVER_PEER_NAME)

        self.client._get_svm_peer_uuid.assert_called_once_with(
            fake.VSERVER_NAME, fake.VSERVER_PEER_NAME)

        self.assertEqual(expected_result, result)

    def test_accept_vserver_peer(self):

        fake_resp = {
            'records': [{'uuid': 'fake-vserver-uuid'}],
            'num_records': 1,
        }

        self.mock_object(
            self.client, 'send_request',
            mock.Mock(side_effect=[fake_resp, None]))
        self.client.accept_vserver_peer(
            fake.VSERVER_NAME, fake.VSERVER_PEER_NAME)

        body = {'state': 'peered'}

        uuid = "fake-vserver-uuid"
        self.client.send_request.assert_has_calls([
            mock.call(f'/svm/peers/{uuid}', 'patch', body=body,
                      enable_tunneling=False)])

    def test_get_vserver_peers(self):
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=fake.FAKE_PEER_GET_RESPONSE))

        result = self.client.get_vserver_peers(
            vserver_name=fake.VSERVER_NAME,
            peer_vserver_name=fake.VSERVER_NAME_2)

        query = {
            'name': fake.VSERVER_NAME_2,
            'svm.name': fake.VSERVER_NAME
        }
        query['fields'] = 'uuid,svm.name,peer.svm.name,state,peer.cluster.name'
        self.client.send_request.assert_has_calls([
            mock.call('/svm/peers', 'get', query=query)])

        expected = [{
            'uuid': fake.FAKE_UUID,
            'vserver': fake.VSERVER_NAME,
            'peer-vserver': fake.VSERVER_NAME_2,
            'peer-state': fake.VSERVER_PEER_STATE,
            'peer-cluster': fake.CLUSTER_NAME
        }]
        self.assertEqual(expected, result)

    def test_get_vserver_peers_not_found(self):

        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=fake.NO_RECORDS_RESPONSE_REST))

        result = self.client.get_vserver_peers(
            vserver_name=fake.VSERVER_NAME,
            peer_vserver_name=fake.VSERVER_NAME_2)

        self.assertEqual([], result)
        self.assertTrue(self.client.send_request.called)

    def test_delete_vserver_peer(self):

        self.mock_object(self.client, 'get_vserver_peers',
                         mock.Mock(return_value=fake.FAKE_VSERVER_PEERS))

        self.mock_object(self.client, 'send_request')

        self.client.delete_vserver_peer(fake.VSERVER_NAME,
                                        fake.VSERVER_PEER_NAME)

        self.client.get_vserver_peers.assert_called_once_with(
            fake.VSERVER_NAME, fake.VSERVER_PEER_NAME)
        self.client.send_request.assert_called_once_with(
            '/svm/peers/fake_uuid', 'delete', enable_tunneling=False)

    def test_update_showmount(self):
        query = {
            'name': fake.VSERVER_NAME,
            'fields': 'uuid'
        }
        response_svm = fake.SVMS_LIST_SIMPLE_RESPONSE_REST
        self.client.vserver = fake.VSERVER_NAME
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(side_effect=[response_svm, None]))

        fake_showmount = 'true'
        self.client.update_showmount(fake_showmount)

        svm_id = response_svm.get('records')[0]['uuid']

        body = {
            'showmount_enabled': fake_showmount,
        }
        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get', query=query),
            mock.call(f'/protocols/nfs/services/{svm_id}',
                      'patch', body=body)
        ])

    @ddt.data({'tcp-max-xfer-size': 10000}, {}, None)
    def test_enable_nfs(self, nfs_config):
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client,
                         '_enable_nfs_protocols')
        self.mock_object(self.client,
                         '_configure_nfs')
        self.mock_object(self.client,
                         '_create_default_nfs_export_rules')

        self.mock_object(self.client, '_enable_nfs_protocols')

        self.client.enable_nfs(fake.NFS_VERSIONS, nfs_config)
        body = {
            'svm.uuid': fake.FAKE_UUID,
            'enabled': 'true'
        }

        self.client.send_request.assert_called_once_with(
            '/protocols/nfs/services/', 'post', body=body)
        self.client._get_unique_svm_by_name.assert_called_once_with()
        self.client._enable_nfs_protocols.assert_called_once_with(
            fake.NFS_VERSIONS, fake.FAKE_UUID)
        if nfs_config:
            self.client._configure_nfs.assert_called_once_with(nfs_config,
                                                               fake.FAKE_UUID)
        else:
            self.client._configure_nfs.assert_not_called()
        self.client._create_default_nfs_export_rules.assert_called_once_with()

    @ddt.data((True, True, True), (True, False, False), (False, True, True))
    @ddt.unpack
    def test_enable_nfs_protocols(self, v3, v40, v41):

        self.mock_object(self.client, 'send_request')

        versions = []
        if v3:
            versions.append('nfs3')
        if v40:
            versions.append('nfs4.0')
        if v41:
            versions.append('nfs4.1')

        self.client._enable_nfs_protocols(versions, fake.FAKE_UUID)

        body = {
            'protocol.v3_enabled': 'true' if v3 else 'false',
            'protocol.v40_enabled': 'true' if v40 else 'false',
            'protocol.v41_enabled': 'true' if v41 else 'false',
            'showmount_enabled': 'true',
            'windows.v3_ms_dos_client_enabled': 'true',
            'protocol.v3_features.connection_drop': 'false',
            'protocol.v3_features.ejukebox_enabled': 'false',
        }
        self.client.send_request.assert_called_once_with(
            f'/protocols/nfs/services/{fake.FAKE_UUID}',
            'patch', body=body)

    def test_configure_nfs(self):
        self.mock_object(self.client, 'send_request')

        fake_nfs = {
            'tcp-max-xfer-size': 10000,
        }
        self.client._configure_nfs(fake_nfs, fake.FAKE_UUID)

        body = {
            'transport.tcp_max_transfer_size': 10000
        }
        self.client.send_request.assert_called_once_with(
            f'/protocols/nfs/services/{fake.FAKE_UUID}',
            'patch', body=body)

    def test__create_default_nfs_export_rules(self):

        class CopyingMock(mock.Mock):
            def __call__(self, *args, **kwargs):
                args = copy.deepcopy(args)
                kwargs = copy.deepcopy(kwargs)
                return super(CopyingMock, self).__call__(*args, **kwargs)

        self.mock_object(self.client, 'send_request', CopyingMock())

        fake_uuid = fake.FAKE_UUID

        mock_id = self.mock_object(self.client, 'get_unique_export_policy_id',
                                   mock.Mock(return_value=fake_uuid))

        self.client._create_default_nfs_export_rules()

        body = {
            'clients': [{
                'match': '0.0.0.0/0'
            }],
            'ro_rule': [
                'any',
            ],
            'rw_rule': [
                'never'
            ],
        }
        body2 = body.copy()
        body2['clients'] = [{
            'match': '::/0'
        }]

        mock_id.assert_called_once_with('default')
        self.client.send_request.assert_has_calls([
            mock.call(f'/protocols/nfs/export-policies/{fake_uuid}/rules',
                      "post", body=body),
            mock.call(f'/protocols/nfs/export-policies/{fake_uuid}/rules',
                      "post", body=body2)])

    def test_get_node_data_ports(self):
        self.mock_object(
            self.client, 'send_request', mock.Mock(
                side_effect=[fake.REST_ETHERNET_PORTS,
                             fake.REST_DATA_INTERFACES]))
        self.mock_object(
            self.client, '_sort_data_ports_by_speed', mock.Mock(
                return_value=fake.REST_SPEED_SORTED_PORTS))

        test_result = self.client.get_node_data_ports(fake.NODE_NAME)

        fake_query = {
            'node.name': fake.NODE_NAME,
            'state': 'up',
            'type': 'physical',
            'broadcast_domain.name': 'Default',
            'fields': 'node.name,speed,name'
        }

        query_interfaces = {
            'service_policy.name': '!default-management',
            'services': 'data_*',
            'fields': 'location.port.name'
        }

        self.client.send_request.assert_has_calls([
            mock.call('/network/ethernet/ports', 'get', query=fake_query),
            mock.call('/network/ip/interfaces', 'get',
                      query=query_interfaces, enable_tunneling=False),
        ])
        self.client._sort_data_ports_by_speed.assert_called_once_with(
            fake.REST_SPEED_NOT_SORTED_PORTS)
        self.assertEqual(fake.REST_SPEED_SORTED_PORTS, test_result)

    def test_list_node_data_ports(self):

        expected_resulted = ['e0d', 'e0c', 'e0b']

        mock_ports = (
            self.mock_object(self.client, 'get_node_data_ports', mock.Mock(
                return_value=fake.REST_SPEED_SORTED_PORTS)))

        test_result = self.client.list_node_data_ports(fake.NODE_NAME)

        mock_ports.assert_called_once_with(fake.NODE_NAME)
        self.assertEqual(test_result, expected_resulted)

    def test_create_ipspace(self):
        fake_body = {'name': fake.IPSPACE_NAME}

        self.mock_object(self.client, 'send_request')

        self.client.create_ipspace(fake.IPSPACE_NAME)

        self.client.send_request.assert_called_once_with(
            '/network/ipspaces', 'post', body=fake_body)

    def test_get_ipspace_name_for_vlan_port(self):

        fake_query = {
            'node.name': fake.NODE_NAME,
            'name': fake.VLAN_PORT,
            'fields': 'broadcast_domain.ipspace.name',
        }

        expected_result = "Default"

        self.mock_object(
            self.client, 'send_request', mock.Mock(
                return_value=fake.REST_ETHERNET_PORTS))

        test_result = self.client.get_ipspace_name_for_vlan_port(
            fake.NODE_NAME, fake.PORT, fake.VLAN)

        self.client.send_request.assert_called_once_with(
            '/network/ethernet/ports/', 'get', query=fake_query)

        self.assertEqual(test_result, expected_result)

    def test__create_broadcast_domain(self):

        fake_body = {
            'ipspace.name': fake.IPSPACE_NAME,
            'name': fake.BROADCAST_DOMAIN,
            'mtu': fake.MTU,
        }

        self.mock_object(self.client, 'send_request')

        self.client._create_broadcast_domain(fake.BROADCAST_DOMAIN,
                                             fake.IPSPACE_NAME,
                                             fake.MTU)

        self.client.send_request.assert_called_once_with(
            '/network/ethernet/broadcast-domains', 'post', body=fake_body)

    def test_ensure_broadcast_domain_for_port_domain_match(self):

        port_info = {
            'ipspace': fake.IPSPACE_NAME,
            'broadcast-domain': fake.BROADCAST_DOMAIN,
        }
        self.mock_object(self.client,
                         '_get_broadcast_domain_for_port',
                         mock.Mock(return_value=port_info))
        self.mock_object(self.client,
                         '_broadcast_domain_exists',
                         mock.Mock(return_value=True))
        self.mock_object(self.client, '_create_broadcast_domain')
        self.mock_object(self.client, '_modify_broadcast_domain')
        self.mock_object(self.client, '_add_port_to_broadcast_domain')

        self.client._ensure_broadcast_domain_for_port(
            fake.NODE_NAME, fake.PORT, fake.MTU, ipspace=fake.IPSPACE_NAME)

        self.client._get_broadcast_domain_for_port.assert_called_once_with(
            fake.NODE_NAME, fake.PORT)
        self.client._modify_broadcast_domain.assert_called_once_with(
            fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME, fake.MTU)
        self.assertFalse(self.client._broadcast_domain_exists.called)
        self.assertFalse(self.client._create_broadcast_domain.called)
        self.assertFalse(self.client._add_port_to_broadcast_domain.called)

    @ddt.data(fake.IPSPACE_NAME, client_cmode.DEFAULT_IPSPACE)
    def test_ensure_broadcast_domain_for_port_other_domain(self, ipspace):

        port_info = {
            'ipspace': ipspace,
            'broadcast-domain': 'other_domain',
        }
        self.mock_object(self.client,
                         '_get_broadcast_domain_for_port',
                         mock.Mock(return_value=port_info))
        self.mock_object(self.client,
                         '_broadcast_domain_exists',
                         mock.Mock(return_value=True))
        self.mock_object(self.client, '_create_broadcast_domain')
        self.mock_object(self.client, '_modify_broadcast_domain')
        self.mock_object(self.client, '_add_port_to_broadcast_domain')

        self.client._ensure_broadcast_domain_for_port(
            fake.NODE_NAME, fake.PORT, ipspace=fake.IPSPACE_NAME, mtu=fake.MTU)

        self.client._get_broadcast_domain_for_port.assert_called_once_with(
            fake.NODE_NAME, fake.PORT)
        self.client._broadcast_domain_exists.assert_called_once_with(
            fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME)
        self.assertFalse(self.client._create_broadcast_domain.called)
        self.client._modify_broadcast_domain.assert_called_once_with(
            fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME, fake.MTU)
        self.client._add_port_to_broadcast_domain.assert_called_once_with(
            fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN,
            fake.IPSPACE_NAME)

    def test_ensure_broadcast_domain_for_port_no_domain(self):

        port_info = {
            'ipspace': fake.IPSPACE_NAME,
            'broadcast-domain': None,
        }
        self.mock_object(self.client,
                         '_get_broadcast_domain_for_port',
                         mock.Mock(return_value=port_info))
        self.mock_object(self.client,
                         '_broadcast_domain_exists',
                         mock.Mock(return_value=False))
        self.mock_object(self.client, '_create_broadcast_domain')
        self.mock_object(self.client, '_modify_broadcast_domain')
        self.mock_object(self.client, '_add_port_to_broadcast_domain')

        self.client._ensure_broadcast_domain_for_port(
            fake.NODE_NAME, fake.PORT, ipspace=fake.IPSPACE_NAME, mtu=fake.MTU)

        self.client._get_broadcast_domain_for_port.assert_called_once_with(
            fake.NODE_NAME, fake.PORT)
        self.client._broadcast_domain_exists.assert_called_once_with(
            fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME)
        self.client._create_broadcast_domain.assert_called_once_with(
            fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME, fake.MTU)
        self.assertFalse(self.client._modify_broadcast_domain.called)
        self.client._add_port_to_broadcast_domain.assert_called_once_with(
            fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN,
            fake.IPSPACE_NAME)

    def test__add_port_to_broadcast_domain(self):
        query = {
            'name': fake.PORT,
            'node.name': fake.NODE_NAME,
        }
        body = {
            'broadcast_domain.ipspace.name': fake.IPSPACE_NAME,
            'broadcast_domain.name': fake.BROADCAST_DOMAIN,
        }

        self.mock_object(self.client, 'send_request')
        self.client._add_port_to_broadcast_domain(fake.NODE_NAME,
                                                  fake.PORT,
                                                  fake.BROADCAST_DOMAIN,
                                                  fake.IPSPACE_NAME)

        self.client.send_request.assert_called_once_with(
            '/network/ethernet/ports/', 'patch', query=query, body=body)

    def test__add_port_to_broadcast_domain_exists(self):
        query = {
            'name': fake.PORT,
            'node.name': fake.NODE_NAME,
        }
        body = {
            'broadcast_domain.ipspace.name': fake.IPSPACE_NAME,
            'broadcast_domain.name': fake.BROADCAST_DOMAIN,
        }
        self.mock_object(
            self.client, 'send_request', self._mock_api_error(
                code=netapp_api.EREST_FAIL_ADD_PORT_BROADCAST))

        self.client._add_port_to_broadcast_domain(fake.NODE_NAME,
                                                  fake.PORT,
                                                  fake.BROADCAST_DOMAIN,
                                                  fake.IPSPACE_NAME)

        self.client.send_request.assert_called_once_with(
            '/network/ethernet/ports/', 'patch', query=query, body=body)
        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)

    def test__add_port_to_broadcast_domain_exception(self):
        self.mock_object(self.client, 'send_request',
                         self._mock_api_error())
        self.assertRaises(
            exception.NetAppException,
            self.client._add_port_to_broadcast_domain,
            fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN,
            fake.IPSPACE_NAME)

    def test_rename_vserver(self):
        svm_uuid = fake.SVM_ITEM_SIMPLE_RESPONSE_REST["uuid"]
        body = {
            'name': fake.VSERVER_NAME_2
        }

        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=svm_uuid))
        self.mock_object(self.client, 'send_request')

        self.client.rename_vserver(fake.VSERVER_NAME, fake.VSERVER_NAME_2)

        self.client._get_unique_svm_by_name.assert_called_once_with(
            fake.VSERVER_NAME)
        self.client.send_request.assert_called_once_with(
            f'/svm/svms/{svm_uuid}', 'patch', body=body)

    def test_create_network_interface(self):
        api_response = copy.deepcopy(fake.SERVICE_POLICIES_REST)
        self.mock_object(
            self.client, 'send_request',
            mock.Mock(side_effect=[api_response, None, None]))

        self.client.create_network_interface(fake.IP_ADDRESS,
                                             fake.NETMASK,
                                             fake.NODE_NAME,
                                             fake.VLAN_PORT,
                                             fake.VSERVER_NAME,
                                             fake.LIF_NAME)
        query = {
            'name': 'default-data-files',
            'svm.name': fake.VSERVER_NAME,
            'fields': 'uuid,name,services,svm.name'
        }

        policy = copy.deepcopy(fake.SERVICE_POLICIES_REST['records'][0])
        uuid = policy['uuid']

        policy['services'].append('data_nfs')
        policy['services'].append('data_cifs')
        body1 = {'services': policy['services']}

        body2 = {
            'ip.address': fake.IP_ADDRESS,
            'ip.netmask': fake.NETMASK,
            'enabled': 'true',
            'service_policy.name': 'default-data-files',
            'location.home_node.name': fake.NODE_NAME,
            'location.home_port.name': fake.VLAN_PORT,
            'name': fake.LIF_NAME,
            'svm.name': fake.VSERVER_NAME,
        }

        self.client.send_request.assert_has_calls([
            mock.call('/network/ip/service-policies/', 'get', query=query),
            mock.call(f'/network/ip/service-policies/{uuid}',
                      'patch', body=body1),
            mock.call('/network/ip/interfaces', 'post', body=body2)
        ])

    def test_create_vserver(self):
        mock = self.mock_object(self.client, '_create_vserver')
        self.mock_object(self.client, '_modify_security_cert',
                         mock.Mock(return_value=[]))
        self.client.create_vserver(fake.VSERVER_NAME, None, None,
                                   [fake.SHARE_AGGREGATE_NAME],
                                   fake.IPSPACE_NAME,
                                   fake.SECURITY_CERT_DEFAULT_EXPIRE_DAYS,
                                   fake.DELETE_RETENTION_HOURS,
                                   False)
        mock.assert_called_once_with(fake.VSERVER_NAME,
                                     [fake.SHARE_AGGREGATE_NAME],
                                     fake.IPSPACE_NAME,
                                     fake.DELETE_RETENTION_HOURS,
                                     name_server_switch=['files'],
                                     logical_space_reporting=False)
        self.client._modify_security_cert.assert_called_once_with(
            fake.VSERVER_NAME,
            fake.SECURITY_CERT_DEFAULT_EXPIRE_DAYS)

    def test__modify_security_cert(self):
        api_response = copy.deepcopy(fake.SECURITY_CERT_GET_RESPONSE_REST)
        api_response2 = copy.deepcopy(fake.SECURITY_CERT_POST_RESPONSE_REST)
        self.mock_object(
            self.client, 'send_request',
            mock.Mock(side_effect=[api_response, api_response2, None, None]))

        query = {
            'common-name': fake.VSERVER_NAME,
            'ca': fake.VSERVER_NAME,
            'type': 'server',
            'svm.name': fake.VSERVER_NAME,
        }
        old_cert_info = copy.deepcopy(
            fake.SECURITY_CERT_GET_RESPONSE_REST['records'][0])
        old_cert_uuid = old_cert_info['uuid']

        body1 = {
            'common-name': fake.VSERVER_NAME,
            'type': 'server',
            'svm.name': fake.VSERVER_NAME,
            'expiry_time': 'P' + str(
                fake.SECURITY_CERT_LARGE_EXPIRE_DAYS) + 'DT',
        }
        query1 = {
            'return_records': 'true'
        }
        new_cert_info = copy.deepcopy(
            fake.SECURITY_CERT_POST_RESPONSE_REST['records'][0])
        new_cert_uuid = new_cert_info['uuid']
        new_svm_uuid = new_cert_info['svm']['uuid']
        body2 = {
            'certificate': {
                'uuid': new_cert_uuid,
            },
            'client_enabled': 'false',
        }

        self.client._modify_security_cert(
            fake.VSERVER_NAME,
            fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)

        self.client.send_request.assert_has_calls([
            mock.call('/security/certificates', 'get', query=query),
            mock.call('/security/certificates', 'post', body=body1,
                      query=query1),
            mock.call(f'/svm/svms/{new_svm_uuid}', 'patch', body=body2),
            mock.call(f'/security/certificates/{old_cert_uuid}', 'delete'),
        ])

    def test__broadcast_domain_exists(self):
        response = fake.FAKE_GET_BROADCAST_DOMAIN
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        query = {
            'ipspace.name': fake.IPSPACE_NAME,
            'name': fake.BROADCAST_DOMAIN,
        }
        result = self.client._broadcast_domain_exists(fake.BROADCAST_DOMAIN,
                                                      fake.IPSPACE_NAME)
        self.client.send_request.assert_called_once_with(
            '/network/ethernet/broadcast-domains',
            'get', query=query)
        self.assertTrue(result)

    def test___delete_port_by_ipspace_and_broadcast_domain(self):
        self.mock_object(self.client, 'send_request')
        query = {
            'broadcast_domain.ipspace.name': fake.IPSPACE_NAME,
            'broadcast_domain.name': fake.BROADCAST_DOMAIN,
            'name': fake.PORT
        }
        self.client._delete_port_by_ipspace_and_broadcast_domain(
            fake.PORT,
            fake.BROADCAST_DOMAIN,
            fake.IPSPACE_NAME)
        self.client.send_request.assert_called_once_with(
            '/network/ethernet/ports/', 'delete',
            query=query)

    def test_get_broadcast_domain_for_port(self):

        self.mock_object(self.client, 'send_request', mock.Mock(
            return_value=fake.REST_ETHERNET_PORTS))

        query = {
            'node.name': fake.NODE_NAME,
            'name': fake.PORT,
            'fields': 'broadcast_domain.name,broadcast_domain.ipspace.name'
        }

        result = self.client._get_broadcast_domain_for_port(fake.NODE_NAME,
                                                            fake.PORT)

        expected = {
            'broadcast-domain': "fake_domain_1",
            'ipspace': "Default",
        }
        self.client.send_request.assert_has_calls([
            mock.call('/network/ethernet/ports', 'get', query=query)])
        self.assertEqual(expected, result)

    def test_modify_broadcast_domain(self):

        self.mock_object(self.client, 'send_request')

        result = self.client._modify_broadcast_domain(fake.BROADCAST_DOMAIN,
                                                      fake.IPSPACE_NAME,
                                                      fake.MTU)

        query = {
            'name': fake.BROADCAST_DOMAIN
        }

        body = {
            'ipspace.name': fake.IPSPACE_NAME,
            'mtu': fake.MTU,
        }
        self.assertIsNone(result)
        self.client.send_request.assert_called_once_with(
            '/network/ethernet/broadcast-domains', 'patch', body=body,
            query=query)

    @ddt.data(fake.NO_RECORDS_RESPONSE,
              fake.SVMS_LIST_SIMPLE_RESPONSE_REST)
    def test_get_vserver_info(self, api_response):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=api_response))

        result = self.client.get_vserver_info(fake.VSERVER_NAME)

        query = {
            'name': fake.VSERVER_NAME,
            'fields': 'state,subtype'
        }
        self.client.send_request.assert_called_once_with(
            '/svm/svms', 'get', query=query)
        if api_response == fake.NO_RECORDS_RESPONSE:
            self.assertIsNone(result)
        else:
            self.assertDictEqual(fake.VSERVER_INFO, result)

    def test_get_nfs_config(self):
        api_response = fake.NFS_CONFIG_RESULT_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))

        result = self.client.get_nfs_config(['tcp-max-xfer-size',
                                             'udp-max-xfer-size'],
                                            fake.VSERVER_NAME)
        expected = {
            'tcp-max-xfer-size': '65536',
            'udp-max-xfer-size': '32768',
        }
        self.assertEqual(expected, result)

        query = {'fields': 'transport.*', 'svm.name': 'fake_vserver'}
        self.client.send_request.assert_called_once_with(
            '/protocols/nfs/services/', 'get', query=query)

    def test_get_vserver_ipspace(self):

        self.client.features.add_feature('IPSPACES')
        api_response = fake.REST_VSERVER_GET_IPSPACE_NAME_RESPONSE
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))

        result = self.client.get_vserver_ipspace(fake.VSERVER_NAME)

        query = {
            'name': fake.VSERVER_NAME,
            'fields': 'ipspace.name'
        }
        expected = fake.IPSPACE_NAME
        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get', query=query)])
        self.assertEqual(expected, result)

    def test_get_vserver_ipspace_not_found(self):
        api_response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=api_response))
        result = self.client.get_vserver_ipspace(fake.VSERVER_NAME)
        self.assertIsNone(result)

    def test_get_vserver_ipspace_exception(self):
        self.mock_object(self.client, 'send_request',
                         self._mock_api_error())
        self.assertRaises(exception.NetAppException,
                          self.client.get_vserver_ipspace,
                          fake.VSERVER_NAME)

    def test_get_snapmirror_policies(self):
        api_response = fake.GET_SNAPMIRROR_POLICIES_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=api_response))
        result_elem = [fake.SNAPMIRROR_POLICY_NAME]

        result = self.client.get_snapmirror_policies(
            fake.VSERVER_NAME)

        query = {
            'svm.name': fake.VSERVER_NAME,
            'fields': 'name'
        }

        self.client.send_request.assert_called_once_with(
            '/snapmirror/policies', 'get', query=query)
        self.assertEqual(result_elem, result)

    def test_delete_snapmirror_policy(self):
        api_response = fake.GET_SNAPMIRROR_POLICIES_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=api_response))

        self.client.delete_snapmirror_policy('fake_policy')

        query = {}
        query['name'] = 'fake_policy'
        query['fields'] = 'uuid,name'
        uuid = fake.FAKE_UUID
        self.client.send_request.assert_has_calls([
            mock.call('/snapmirror/policies', 'get', query=query),
            mock.call(f'/snapmirror/policies/{uuid}', 'delete')
        ])

    def test_delete_snapmirror_policy_exception(self):
        api_response = fake.GET_SNAPMIRROR_POLICIES_REST
        api_error = netapp_api.api.NaApiError()
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=[api_response, api_error]))
        self.assertRaises(netapp_api.api.NaApiError,
                          self.client.delete_snapmirror_policy,
                          'fake_policy')

    def test_delete_snapmirror_policy_no_records(self):
        api_response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=api_response))

        self.client.delete_snapmirror_policy('fake_policy')

        query = {}
        query['name'] = 'fake_policy'
        query['fields'] = 'uuid,name'
        self.client.send_request.assert_called_once_with(
            '/snapmirror/policies', 'get', query=query)

    def test_delete_vserver_one_volume(self):
        self.mock_object(self.client, 'get_vserver_info',
                         mock.Mock(return_value=fake.VSERVER_INFO))
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        self.mock_object(self.client, 'get_vserver_root_volume_name',
                         mock.Mock(return_value=fake.ROOT_VOLUME_NAME))
        self.mock_object(self.client, 'get_vserver_volume_count',
                         mock.Mock(return_value=1))
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, 'offline_volume')
        self.mock_object(self.client, 'delete_volume')
        self.mock_object(self.client, '_terminate_vserver_services')

        self.client.delete_vserver(fake.VSERVER_NAME, self.client,
                                   fake.CIFS_SECURITY_SERVICE)

        self.client.offline_volume.assert_called_with(fake.ROOT_VOLUME_NAME)
        self.client.delete_volume.assert_called_with(fake.ROOT_VOLUME_NAME)
        self.client._terminate_vserver_services(
            fake.VSERVER_NAME, self.client, fake.CIFS_SECURITY_SERVICE)

        svm_uuid = fake.FAKE_UUID
        self.client.send_request.assert_has_calls([
            mock.call(f'/svm/svms/{svm_uuid}', 'delete')])

    def test_delete_vserver_one_volume_already_offline(self):

        self.mock_object(self.client,
                         'get_vserver_info',
                         mock.Mock(return_value=fake.VSERVER_INFO))
        self.mock_object(self.client,
                         '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        self.mock_object(self.client,
                         'get_vserver_root_volume_name',
                         mock.Mock(return_value=fake.ROOT_VOLUME_NAME))
        self.mock_object(self.client,
                         'get_vserver_volume_count',
                         mock.Mock(return_value=1))
        self.mock_object(self.client,
                         'offline_volume',
                         self._mock_api_error(
                             code=netapp_api.EREST_ENTRY_NOT_FOUND))
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, 'delete_volume')

        self.client.delete_vserver(fake.VSERVER_NAME,
                                   self.client)

        self.client.offline_volume.assert_called_with(
            fake.ROOT_VOLUME_NAME)
        self.client.delete_volume.assert_called_with(
            fake.ROOT_VOLUME_NAME)

        svm_uuid = fake.FAKE_UUID
        self.client.send_request.assert_has_calls([
            mock.call(f'/svm/svms/{svm_uuid}', 'delete')])
        self.assertEqual(1, client_cmode_rest.LOG.error.call_count)

    def test_delete_vserver_one_volume_api_error(self):

        self.mock_object(self.client,
                         'get_vserver_info',
                         mock.Mock(return_value=fake.VSERVER_INFO))
        self.mock_object(self.client,
                         '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        self.mock_object(self.client,
                         'get_vserver_root_volume_name',
                         mock.Mock(return_value=fake.ROOT_VOLUME_NAME))
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client,
                         'get_vserver_volume_count',
                         mock.Mock(return_value=1))
        self.mock_object(self.client,
                         'offline_volume',
                         self._mock_api_error())
        self.mock_object(self.client, 'delete_volume')

        self.assertRaises(netapp_api.api.NaApiError,
                          self.client.delete_vserver,
                          fake.VSERVER_NAME,
                          self.client)

    def test_delete_vserver_multiple_volumes(self):

        self.mock_object(self.client,
                         'get_vserver_info',
                         mock.Mock(return_value=fake.VSERVER_INFO))
        self.mock_object(self.client,
                         '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        self.mock_object(self.client,
                         'get_vserver_root_volume_name',
                         mock.Mock(return_value=fake.ROOT_VOLUME_NAME))
        self.mock_object(self.client,
                         'get_vserver_volume_count',
                         mock.Mock(return_value=2))

        self.assertRaises(exception.NetAppException,
                          self.client.delete_vserver,
                          fake.VSERVER_NAME,
                          self.client)

    def test_delete_vserver_not_found(self):

        self.mock_object(self.client,
                         'get_vserver_info',
                         mock.Mock(return_value=None))
        self.mock_object(self.client,
                         '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))

        self.client.delete_vserver(fake.VSERVER_NAME,
                                   self.client)

        self.assertEqual(1, client_cmode_rest.LOG.error.call_count)

    def test_get_vserver_volume_count(self):
        fake_response = fake.VOLUME_GET_ITER_RESPONSE_REST_PAGE
        mock_request = self.mock_object(self.client, 'send_request',
                                        mock.Mock(return_value=fake_response))
        response = self.client.get_vserver_volume_count()

        self.assertEqual(response, 10)
        query = {'return_records': 'false'}
        mock_request.assert_called_once_with(
            '/storage/volumes', 'get', query=query)

    def test__terminate_vserver_services(self):

        fake_uuid = fake.FAKE_UUID

        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, 'disable_kerberos')
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake_uuid))

        security_services = [
            copy.deepcopy(fake.CIFS_SECURITY_SERVICE),
            copy.deepcopy(fake.KERBEROS_SECURITY_SERVICE)
        ]
        self.client._terminate_vserver_services(
            fake.VSERVER_NAME, self.client, security_services)

        cifs_server_delete_body = {
            'ad_domain.password': security_services[0]['password'],
            'ad_domain.user': security_services[0]['user'],
        }
        self.client.send_request.assert_called_once_with(
            f'/protocols/cifs/services/{fake_uuid}', 'delete',
            body=cifs_server_delete_body)
        self.client.disable_kerberos.assert_called_once_with(
            security_services[1])

    def test_terminate_vserver_services_cifs_not_found(self):

        fake_uuid = fake.FAKE_UUID

        self.mock_object(
            self.client, 'send_request',
            self._mock_api_error(code=netapp_api.EREST_ENTRY_NOT_FOUND))
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake_uuid))

        security_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
        self.client._terminate_vserver_services(fake.VSERVER_NAME,
                                                self.client,
                                                [security_service])

        cifs_server_delete_body = {
            'ad_domain.password': security_service['password'],
            'ad_domain.user': security_service['user'],
        }
        self.client.send_request.assert_called_once_with(
            f'/protocols/cifs/services/{fake_uuid}', 'delete',
            body=cifs_server_delete_body)
        self.assertEqual(1, client_cmode_rest.LOG.error.call_count)

    def test_terminate_vserver_services_api_error(self):

        fake_uuid = fake.FAKE_UUID
        side_effects = [netapp_api.api.NaApiError(code='fake'), None]

        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(side_effect=side_effects))
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake_uuid))

        security_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
        self.client._terminate_vserver_services(fake.VSERVER_NAME,
                                                self.client,
                                                [security_service])

        cifs_server_delete_body = {
            'ad_domain.password': security_service['password'],
            'ad_domain.user': security_service['user'],
        }
        cifs_server_delete_force_body = {
            'ad_domain.password': security_service['password'],
            'ad_domain.user': security_service['user'],
            'force': True
        }

        self.client.send_request.assert_has_calls([
            mock.call(f'/protocols/cifs/services/{fake_uuid}', 'delete',
                      body=cifs_server_delete_body),
            mock.call(f'/protocols/cifs/services/{fake_uuid}', 'delete',
                      body=cifs_server_delete_force_body)])
        self.assertEqual(0, client_cmode_rest.LOG.error.call_count)

    def test_disable_kerberos(self):
        fake_api_response = fake.NFS_LIFS_REST
        api_error = self._mock_api_error(
            code=netapp_api.EREST_KERBEROS_IS_ENABLED_DISABLED)
        self.mock_object(self.client, 'get_network_interfaces',
                         mock.Mock(return_value=fake_api_response))
        self.mock_object(
            self.client, 'send_request',
            mock.Mock(side_effect=[None, api_error, None]))

        self.client.disable_kerberos(fake.KERBEROS_SECURITY_SERVICE)

        kerberos_config_modify_body = {
            'password': fake.KERBEROS_SECURITY_SERVICE['password'],
            'user': fake.KERBEROS_SECURITY_SERVICE['user'],
            'interface.name': fake.LIF_NAME,
            'enabled': False,
        }

        self.client.send_request.assert_has_calls([
            mock.call('/protocols/nfs/kerberos/interfaces/fake_uuid_1',
                      'patch', body=kerberos_config_modify_body),
            mock.call('/protocols/nfs/kerberos/interfaces/fake_uuid_2',
                      'patch', body=kerberos_config_modify_body),
            mock.call('/protocols/nfs/kerberos/interfaces/fake_uuid_3',
                      'patch', body=kerberos_config_modify_body)
        ])
        self.client.get_network_interfaces.assert_called_once()

    def test_get_vserver_root_volume_name(self):
        response = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=response))
        self.client.get_vserver_root_volume_name(fake.VSERVER_NAME)
        self.client._get_volume_by_args.assert_called_once_with(
            vserver=fake.VSERVER_NAME, is_root=True)

    def test_ipspace_has_data_vservers(self):
        api_response = fake.REST_VSERVER_GET_IPSPACE_NAME_RESPONSE
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))

        result = self.client.ipspace_has_data_vservers(fake.IPSPACE_NAME)

        query = {'ipspace.name': fake.IPSPACE_NAME}
        self.client.send_request.assert_has_calls([
            mock.call('/svm/svms', 'get', query=query)])
        self.assertTrue(result)

    def test_ipspace_has_data_vservers_not_supported(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value='fake_response'))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=False))

        result = self.client.ipspace_has_data_vservers(fake.IPSPACE_NAME)

        self.assertFalse(result)
        query = {'ipspace.name': fake.IPSPACE_NAME}
        self.client.send_request.assert_called_once_with(
            '/svm/svms', 'get', query=query)
        self.client._has_records.assert_called_once_with('fake_response')

    def test_ipspace_has_data_vservers_not_found(self):
        api_response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))

        result = self.client.ipspace_has_data_vservers(fake.IPSPACE_NAME)

        self.assertFalse(result)

    def test_delete_vlan(self):
        self.mock_object(self.client, 'send_request')

        query = {
            'vlan.base_port.name': fake.PORT,
            'node.name': fake.NODE_NAME,
            'vlan.tag': fake.VLAN
        }

        self.client.delete_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)

        self.client.send_request.assert_has_calls([
            mock.call('/network/ethernet/ports/', 'delete', query=query)])

    def test_delete_vlan_not_found(self):
        self.mock_object(
            self.client, 'send_request',
            self._mock_api_error(code=netapp_api.EREST_ENTRY_NOT_FOUND))

        query = {
            'vlan.base_port.name': fake.PORT,
            'node.name': fake.NODE_NAME,
            'vlan.tag': fake.VLAN
        }

        self.client.delete_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)

        self.client.send_request.assert_has_calls([
            mock.call('/network/ethernet/ports/', 'delete', query=query)])
        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)

    def test_delete_vlan_still_used(self):
        self.mock_object(
            self.client, 'send_request',
            self._mock_api_error(code=netapp_api.EREST_PORT_IN_USE))

        query = {
            'vlan.base_port.name': fake.PORT,
            'node.name': fake.NODE_NAME,
            'vlan.tag': fake.VLAN
        }

        self.client.delete_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)

        self.client.send_request.assert_has_calls([
            mock.call('/network/ethernet/ports/', 'delete', query=query)])
        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)

    def test_delete_vlan_api_error(self):
        self.mock_object(self.client, 'send_request', self._mock_api_error())
        self.assertRaises(exception.NetAppException,
                          self.client.delete_vlan,
                          fake.NODE_NAME,
                          fake.PORT,
                          fake.VLAN)

    @ddt.data(None, fake.IPSPACE_NAME)
    def test_svm_migration_start(self, dest_ipspace):
        check_only = True
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value='fake_migration'))

        res = self.client.svm_migration_start(
            fake.CLUSTER_NAME, fake.VSERVER_NAME, fake.SHARE_AGGREGATE_NAMES,
            dest_ipspace=dest_ipspace, check_only=check_only)

        self.assertEqual('fake_migration', res)
        expected_body = {
            "auto_cutover": False,
            "auto_source_cleanup": True,
            "check_only": True,
            "source": {
                "cluster": {"name": fake.CLUSTER_NAME},
                "svm": {"name": fake.VSERVER_NAME},
            },
            "destination": {
                "volume_placement": {
                    "aggregates": fake.SHARE_AGGREGATE_NAMES,
                },
            },
        }
        if dest_ipspace is not None:
            ipspace_data = {
                "ipspace": {
                    "name": dest_ipspace,
                }
            }
            expected_body["destination"].update(ipspace_data)
        self.client.send_request.assert_called_once_with(
            '/svm/migrations', 'post', body=expected_body,
            wait_on_accepted=False)

    def test_get_migration_check_job_state(self):
        self.mock_object(self.client, 'get_job',
                         mock.Mock(return_value='fake_job'))

        res = self.client.get_migration_check_job_state(fake.JOB_ID)

        self.assertEqual('fake_job', res)
        self.client.get_job.assert_called_once_with(fake.JOB_ID)

    @ddt.data(netapp_api.api.ENFS_V4_0_ENABLED_MIGRATION_FAILURE,
              netapp_api.api.EVSERVER_MIGRATION_TO_NON_AFF_CLUSTER, 'none')
    def test_get_migration_check_job_state_raise_error(self, error_code):
        e = netapp_api.api.NaApiError(code=error_code)
        self.mock_object(self.client, 'get_job', mock.Mock(side_effect=e))

        self.assertRaises(
            exception.NetAppException,
            self.client.get_migration_check_job_state,
            fake.JOB_ID)

    def test_svm_migrate_complete(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value='fake_migration'))

        res = self.client.svm_migrate_complete(fake.FAKE_MIGRATION_POST_ID)

        self.assertEqual('fake_migration', res)
        expected_body = {
            "action": "cutover"
        }
        self.client.send_request.assert_called_once_with(
            f'/svm/migrations/{fake.FAKE_MIGRATION_POST_ID}', 'patch',
            body=expected_body, wait_on_accepted=False)

    def test_svm_migrate_cancel(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value='fake_migration'))

        res = self.client.svm_migrate_cancel(fake.FAKE_MIGRATION_POST_ID)

        self.assertEqual('fake_migration', res)
        self.client.send_request.assert_called_once_with(
            f'/svm/migrations/{fake.FAKE_MIGRATION_POST_ID}', 'delete',
            wait_on_accepted=False)

    def test_svm_migration_get(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value='fake_migration'))

        res = self.client.svm_migration_get(fake.FAKE_MIGRATION_POST_ID)

        self.assertEqual('fake_migration', res)
        self.client.send_request.assert_called_once_with(
            f'/svm/migrations/{fake.FAKE_MIGRATION_POST_ID}', 'get')

    def test_svm_migrate_pause(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value='fake_migration'))

        res = self.client.svm_migrate_pause(fake.FAKE_MIGRATION_POST_ID)

        self.assertEqual('fake_migration', res)
        expected_body = {
            "action": "pause"
        }
        self.client.send_request.assert_called_once_with(
            f'/svm/migrations/{fake.FAKE_MIGRATION_POST_ID}', 'patch',
            body=expected_body, wait_on_accepted=False)

    def test_delete_network_interface(self):
        self.mock_object(self.client, 'disable_network_interface')
        self.mock_object(self.client, 'send_request')

        self.client.delete_network_interface(fake.VSERVER_NAME, fake.LIF_NAME)

        self.client.disable_network_interface.assert_called_once_with(
            fake.VSERVER_NAME, fake.LIF_NAME)
        expected_query = {
            'svm.name': fake.VSERVER_NAME,
            'name': fake.LIF_NAME
        }
        self.client.send_request.assert_called_once_with(
            '/network/ip/interfaces', 'delete', query=expected_query)

    def test_disable_network_interface(self):
        self.mock_object(self.client, 'send_request')

        self.client.disable_network_interface(fake.VSERVER_NAME, fake.LIF_NAME)

        expected_body = {
            'enabled': 'false'
        }
        expected_query = {
            'svm.name': fake.VSERVER_NAME,
            'name': fake.LIF_NAME
        }
        self.client.send_request.assert_called_once_with(
            '/network/ip/interfaces', 'patch', body=expected_body,
            query=expected_query)

    def test__delete_port_and_broadcast_domain(self):

        domain = copy.deepcopy(fake.BROADCAST_DOMAIN)
        ipspace = copy.deepcopy(fake.GET_IPSPACES_RESPONSE)

        query = {'name': domain, 'ipspace.name': ipspace['ipspace']}

        response_broadcast = copy.deepcopy(
            fake.BROADCAST_DOMAIN_LIST_SIMPLE_RESPONSE_REST)
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(side_effect=[response_broadcast, None]))

        self.mock_object(self.client,
                         '_delete_port_by_ipspace_and_broadcast_domain')

        self.client._delete_port_and_broadcast_domain(domain, ipspace)
        self.client.send_request.assert_has_calls([
            mock.call('/network/ethernet/broadcast-domains',
                      'delete', query=query)])

    def test_delete_ipspace(self):
        ipspace = copy.deepcopy(fake.IPSPACES[0])
        mock_del_brcst = self.mock_object(
            self.client, '_delete_port_and_broadcast_domains_for_ipspace')
        self.mock_object(self.client, 'ipspace_has_data_vservers',
                         mock.Mock(return_value=[]))
        mock_send_request = self.mock_object(self.client, 'send_request')

        query = {'name': fake.IPSPACE_NAME}

        self.client.delete_ipspace(ipspace['ipspace'])

        mock_del_brcst.assert_called_once_with(fake.IPSPACE_NAME)

        mock_send_request.assert_called_once_with(
            '/network/ipspaces', 'delete', query=query)

    def test_get_ipspaces(self):
        expected = copy.deepcopy(fake.GET_IPSPACES_RESPONSE)
        sr_responses = [fake.IPSPACE_INFO,
                        fake.REST_SINGLE_PORT,
                        fake.SVMS_LIST_SIMPLE_RESPONSE_REST,
                        fake.FAKE_GET_BROADCAST_DOMAIN]
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=sr_responses))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        result = self.client.get_ipspaces(fake.IPSPACE_NAME)
        self.assertEqual(expected, result)

    def test_get_ipspaces_no_records(self):
        api_response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=api_response))
        result = self.client.get_ipspaces(fake.IPSPACE_NAME)
        self.assertEqual([], result)

    def test_delete_port_and_broadcast_domains_for_ipspace_not_found(self):

        self.mock_object(self.client,
                         'get_ipspaces',
                         mock.Mock(return_value=[]))
        self.mock_object(self.client, '_delete_port_and_broadcast_domain')

        self.client._delete_port_and_broadcast_domains_for_ipspace(
            fake.IPSPACE_NAME)

        self.client.get_ipspaces.assert_called_once_with(
            fake.IPSPACE_NAME)
        self.assertFalse(self.client._delete_port_and_broadcast_domain.called)

    def test_delete_port_and_broadcast_domains_for_ipspace(self):

        self.mock_object(self.client,
                         'get_ipspaces',
                         mock.Mock(return_value=fake.IPSPACES[0]))
        self.mock_object(self.client, '_delete_port_and_broadcast_domain')

        self.client._delete_port_and_broadcast_domains_for_ipspace(
            fake.IPSPACE_NAME)

        self.client.get_ipspaces.assert_called_once_with(
            fake.IPSPACE_NAME)
        self.client._delete_port_and_broadcast_domain.assert_called_once_with(
            fake.IPSPACES[0]['broadcast-domains'][0], fake.IPSPACES[0])

    @ddt.data(('10.10.10.0/24', '10.10.10.1', False),
              ('fc00::/7', 'fe80::1', False),
              ('0.0.0.0/0', '10.10.10.1', True),
              ('::/0', 'fe80::1', True))
    @ddt.unpack
    def test_create_route(self, subnet, gateway, omit_destination):

        address = None
        netmask = None
        destination = None if omit_destination else subnet
        if not destination:
            if netutils.is_valid_ipv6(destination):
                destination = '::/0'
            else:
                destination = '0.0.0.0/0'

        if '/' in destination:
            address, netmask = destination.split('/')
        else:
            address = destination

        body = {
            'destination.address': address,
            'gateway': gateway,
        }

        if netmask:
            body['destination.netmask'] = netmask

        self.mock_object(self.client, 'send_request')

        self.client.create_route(gateway, destination=destination)

        self.client.send_request.assert_called_once_with(
            '/network/ip/routes', 'post', body=body)

    def test_create_route_duplicate(self):
        self.mock_object(client_cmode_rest.LOG, 'debug')
        self.mock_object(
            self.client, 'send_request',
            self._mock_api_error(code=netapp_api.EREST_DUPLICATE_ROUTE))

        self.client.create_route(fake.GATEWAY, destination=fake.SUBNET)

        body = {
            'destination.address': fake.SUBNET[:-3],
            'gateway': fake.GATEWAY,
            'destination.netmask': fake.SUBNET[-2:],
        }
        self.client.send_request.assert_called_once_with(
            '/network/ip/routes', 'post', body=body)
        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)

    def test_create_route_api_error(self):
        self.mock_object(client_cmode_rest.LOG, 'debug')
        self.mock_object(self.client, 'send_request', self._mock_api_error())

        body = {
            'destination.address': fake.SUBNET[:-3],
            'gateway': fake.GATEWAY,
            'destination.netmask': fake.SUBNET[-2:],
        }
        self.assertRaises(exception.NetAppException,
                          self.client.create_route,
                          fake.GATEWAY, destination=fake.SUBNET)
        self.client.send_request.assert_called_once_with(
            '/network/ip/routes', 'post', body=body)

    def test_create_route_without_gateway(self):
        self.mock_object(self.client, 'send_request')
        self.client.create_route(None, destination=fake.SUBNET)
        self.assertFalse(self.client.send_request.called)

    def test_network_interface_exists(self):
        api_response = fake.GENERIC_NETWORK_INTERFACES_GET_REPONSE
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=api_response))
        result = self.client.network_interface_exists(
            fake.VSERVER_NAME, fake.NODE_NAME, fake.PORT, fake.IP_ADDRESS,
            fake.NETMASK, fake.VLAN)
        query = {
            'ip.address': fake.IP_ADDRESS,
            'location.home_node.name': fake.NODE_NAME,
            'location.home_port.name': f'{fake.PORT}-{fake.VLAN}',
            'ip.netmask': fake.NETMASK,
            'svm.name': fake.VSERVER_NAME,
            'fields': 'name',
        }
        self.client.send_request.assert_called_once_with(
            '/network/ip/interfaces', 'get', query=query)
        self.assertTrue(result)

    def test_modify_active_directory_security_service(self):
        svm_uuid = fake.FAKE_UUID
        user_records = fake.FAKE_CIFS_LOCAL_USER.get('records')[0]
        sid = user_records.get('sid')
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=svm_uuid))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=[user_records,
                                                None, None]))
        self.mock_object(self.client, 'remove_preferred_dcs')
        self.mock_object(self.client, 'set_preferred_dc')
        new_security_service = {
            'user': 'new_user',
            'password': 'new_password',
            'server': 'fake_server'
        }

        current_security_service = {
            'server': 'fake_current_server'
        }
        keys = {'user', 'password', 'server'}

        self.client.modify_active_directory_security_service(
            fake.VSERVER_NAME, keys, new_security_service,
            current_security_service)

        self.client.send_request.assert_has_calls([
            mock.call(f'/protocols/cifs/local-users/{svm_uuid}', 'get'),
            mock.call(f'/protocols/cifs/local-users/{svm_uuid}/{sid}', 'patch',
                      query={'password': new_security_service['password']}),
            mock.call(f'/protocols/cifs/local-users/{svm_uuid}/{sid}', 'patch',
                      query={'name': new_security_service['user']})
        ])

    @ddt.data(True, False)
    def test__create_vserver(self, logical_space_reporting):
        mock_sr = self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        body_post = {
            'name': fake.VSERVER_NAME,
            'nsswitch.namemap': fake.FAKE_SERVER_SWITCH_NAME,
            'subtype': fake.FAKE_SUBTYPE,
            'ipspace.name': fake.IPSPACE_NAME,
            'aggregates': [{
                'name': fake.SHARE_AGGREGATE_NAME
            }],
        }

        if logical_space_reporting:
            body_post.update({
                'is_space_reporting_logical': 'true',
                'is_space_enforcement_logical': 'true',
                })
        else:
            body_post.update({
                'is_space_reporting_logical': 'false',
                'is_space_enforcement_logical': 'false',
                })

        body_patch = {
            'retention_period': fake.DELETE_RETENTION_HOURS,
        }

        self.client._create_vserver(
            fake.VSERVER_NAME,
            [fake.SHARE_AGGREGATE_NAME],
            fake.IPSPACE_NAME,
            fake.DELETE_RETENTION_HOURS,
            fake.FAKE_SERVER_SWITCH_NAME,
            fake.FAKE_SUBTYPE,
            logical_space_reporting=logical_space_reporting)

        mock_sr.assert_has_calls([
            mock.call('/svm/svms', 'post', body=body_post),
            mock.call(f'/svm/svms/{fake.FAKE_UUID}', 'patch', body=body_patch)
        ])

    @ddt.data(0, 65535, 270000)
    def test__create_vserver_delete_retention_hours(self,
                                                    delete_retention_hours):
        mock_sr = self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        body_post = {
            'name': fake.VSERVER_NAME,
            'nsswitch.namemap': fake.FAKE_SERVER_SWITCH_NAME,
            'subtype': fake.FAKE_SUBTYPE,
            'ipspace.name': fake.IPSPACE_NAME,
            'is_space_reporting_logical': 'false',
            'is_space_enforcement_logical': 'false',
            'aggregates': [{
                'name': fake.SHARE_AGGREGATE_NAME
            }],
        }

        body_patch = {
            'retention_period': delete_retention_hours,
        }

        self.client._create_vserver(
            fake.VSERVER_NAME,
            [fake.SHARE_AGGREGATE_NAME],
            fake.IPSPACE_NAME,
            delete_retention_hours,
            fake.FAKE_SERVER_SWITCH_NAME,
            fake.FAKE_SUBTYPE)

        mock_sr.assert_has_calls([
            mock.call('/svm/svms', 'post', body=body_post),
            mock.call(f'/svm/svms/{fake.FAKE_UUID}', 'patch', body=body_patch)
        ])

    def test_create_barbican_kms_config_for_specified_vserver(self):
        mock_sr = self.mock_object(self.client, 'send_request')
        body = {
            'svm.name': fake.VSERVER_NAME,
            'configuration.name': fake.FAKE_CONFIG_NAME,
            'key_id': fake.FAKE_KEY_ID,
            'keystone_url': fake.FAKE_KEYSTONE_URL,
            'application_cred_id': fake.FAKE_APPLICATION_CRED_ID,
            'application_cred_secret': fake.FAKE_APPLICATION_CRED_SECRET,
        }

        self.client.create_barbican_kms_config_for_specified_vserver(
            fake.VSERVER_NAME,
            fake.FAKE_CONFIG_NAME,
            fake.FAKE_KEY_ID,
            fake.FAKE_KEYSTONE_URL,
            fake.FAKE_APPLICATION_CRED_ID,
            fake.FAKE_APPLICATION_CRED_SECRET)

        mock_sr.assert_called_once_with('/security/barbican-kms', 'post',
                                        body=body)

    def test_get_key_store_config_uuid(self):
        fake_query = {
            'configuration.name': fake.FAKE_CONFIG_NAME
        }

        self.mock_object(
            self.client, 'send_request', mock.Mock(
                return_value=fake.KEYSTORE_SIMPLE_RESPONSE_REST))

        actual_result = self.client.get_key_store_config_uuid(
            fake.FAKE_CONFIG_NAME)

        self.client.send_request.assert_called_once_with(
            '/security/key-stores', 'get', query=fake_query)

        expected_result = (
            fake.KEYSTORE_SIMPLE_RESPONSE_REST[
                'records'][0]['configuration']['uuid'])
        self.assertEqual(expected_result, actual_result)

    def test_get_key_store_config_uuid_no_response(self):

        self.mock_object(
            self.client, 'send_request', mock.Mock(
                return_value={}))

        actual_result = self.client.get_key_store_config_uuid(
            fake.FAKE_CONFIG_NAME)

        self.assertIsNone(actual_result)

    def test_enable_key_store_config(self):
        config_uuid = fake.FAKE_CONFIG_UUID
        mock_sr = self.mock_object(self.client, 'send_request')
        self.client.enable_key_store_config(config_uuid)
        body = {
            'enabled': True,
        }

        mock_sr.assert_called_once_with(
            f'/security/key-stores/{config_uuid}', 'patch', body=body)

    @ddt.data((f'/name-services/dns/{fake.FAKE_UUID}', 'patch',
               ['fake_domain'], ['fake_ip']),
              (f'/name-services/dns/{fake.FAKE_UUID}', 'delete', [], []),
              ('/name-services/dns', 'post', ['fake_domain'], ['fake_ip']))
    @ddt.unpack
    def test_update_dns_configuration_all_operations(self, endpoint,
                                                     operation, domains, ips):
        return_value = fake.FAKE_DNS_CONFIG if operation != 'post' else {}
        self.mock_object(self.client, 'get_dns_config',
                         mock.Mock(return_value=return_value))
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        mock_sr = self.mock_object(self.client, 'send_request')
        body = {
            'domains': domains,
            'servers': ips
        }
        empty_dns_config = (not body['domains'] and not body['servers'])
        if empty_dns_config:
            body = {}
        self.client.update_dns_configuration(ips, domains)
        mock_sr.assert_called_once_with(endpoint, operation, body)

    @ddt.data(True, False)
    def test_delete_snapshot(self, ignore_owners):
        volume_id = fake.VOLUME.get('uuid')
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=fake.VOLUME))
        response = fake.SNAPSHOTS_REST_RESPONSE
        snapshot_id = response.get('records')[0].get('uuid')
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        query = {
            'name': fake.SNAPSHOT_NAME,
            'fields': 'uuid'
        }
        calls = [mock.call(f'/storage/volumes/{volume_id}/snapshots', 'get',
                           query=query)]
        if ignore_owners:
            query_cli = {
                'vserver': self.client.vserver,
                'volume': fake.VOLUME_NAMES[0],
                'snapshot': fake.SNAPSHOT_NAME,
                'ignore-owners': 'true'
            }
            calls.append(mock.call('/private/cli/snapshot', 'delete',
                                   query=query_cli))
        else:
            calls.append(mock.call(f'/storage/volumes/{volume_id}/'
                                   f'snapshots/{snapshot_id}', 'delete'))

        self.client.delete_snapshot(fake.VOLUME_NAMES[0], fake.SNAPSHOT_NAME,
                                    ignore_owners)
        mock_sr.assert_has_calls(calls)

    def test_soft_delete_snapshot(self):

        mock_delete_snapshot = self.mock_object(self.client, 'delete_snapshot')
        mock_rename_snapshot = self.mock_object(self.client, 'rename_snapshot')

        self.client.soft_delete_snapshot(fake.SHARE_NAME, fake.SNAPSHOT_NAME)

        mock_delete_snapshot.assert_called_once_with(
            fake.SHARE_NAME, fake.SNAPSHOT_NAME)
        self.assertFalse(mock_rename_snapshot.called)

    def test_volume_has_luns(self):
        mock_sr = self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        result = self.client.volume_has_luns(fake.VOLUME_NAMES[0])
        query = {
            'location.volume.name': fake.VOLUME_NAMES[0],
        }
        mock_sr.assert_called_once_with('/storage/luns/', 'get', query=query)
        self.assertTrue(result)

    @ddt.data(fake.VOLUME_JUNCTION_PATH, '')
    def test_volume_has_junctioned_volumes(self, junction_path):
        mock_sr = self.mock_object(self.client, 'send_request')
        return_records = True if junction_path else False
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=return_records))
        result = self.client.volume_has_junctioned_volumes(junction_path)
        if junction_path:
            query = {
                'nas.path': junction_path + '/*',
            }

            mock_sr.assert_called_once_with('/storage/volumes/', 'get',
                                            query=query)
            self.assertTrue(result)
        else:
            self.assertFalse(result)

    @ddt.data(fake.VOLUME_JUNCTION_PATH, '')
    def test_get_volume_at_junction_path(self, junction_path):
        response = fake.VOLUME_LIST_SIMPLE_RESPONSE_REST
        return_records = True if junction_path else False
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=return_records))
        query = {
            'nas.path': junction_path,
            'fields': 'name'
        }

        result = self.client.get_volume_at_junction_path(junction_path)
        expected = {
            'name': response.get('records')[0].get('name')
        }

        if junction_path:
            mock_sr.assert_called_once_with('/storage/volumes/', 'get',
                                            query=query)
            self.assertEqual(expected, result)
        else:
            self.assertIsNone(result)

    def test_get_aggregate_for_volume(self):
        response = fake.FAKE_SVM_AGGREGATES.get('records')[0]
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=response))
        result = self.client.get_aggregate_for_volume(fake.VOLUME_NAMES[0])
        expected = fake.SHARE_AGGREGATE_NAMES_LIST
        query = {
            'name': fake.VOLUME_NAMES[0],
            'fields': 'aggregates'
        }
        mock_sr.assert_called_once_with('/storage/volumes/', 'get',
                                        query=query)
        self.assertEqual(expected, result)

    def test_get_volume_to_manage(self):
        response = fake.FAKE_VOLUME_MANAGE
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        expected = {
            'aggregate': fake.SHARE_AGGREGATE_NAME,
            'aggr-list': [],
            'junction-path': fake.VOLUME_JUNCTION_PATH,
            'name': fake.VOLUME_NAMES[0],
            'type': 'fake_type',
            'style': 'flex',
            'owning-vserver-name': fake.VSERVER_NAME,
            'size': fake.SHARE_SIZE,
            'qos-policy-group-name': fake.QOS_POLICY_GROUP_NAME,
            'created_at': fake.CREATE_TIME_ISO
        }

        result = self.client.get_volume_to_manage(fake.SHARE_AGGREGATE_NAME,
                                                  fake.VOLUME_NAMES[0])
        query = {
            'name': fake.VOLUME_NAMES[0],
            'fields': 'name,aggregates.name,nas.path,name,type,style,'
                      'svm.name,qos.policy.name,space.size,create_time',
            'aggregates.name': fake.SHARE_AGGREGATE_NAME
        }
        mock_sr.assert_called_once_with('/storage/volumes', 'get',
                                        query=query)
        self.assertEqual(expected, result)

    def test_get_cifs_share_access(self):
        response = fake.FAKE_CIFS_RECORDS
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=response))
        query = {
            'name': fake.SHARE_NAME
        }
        query_acls = {
            'fields': 'user_or_group,permission'
        }
        expected = {
            'Everyone': 'full_control',
            'root': 'no_access'
        }
        result = self.client.get_cifs_share_access(fake.SHARE_NAME)
        svm_uuid = response.get('records')[0].get('svm').get('uuid')
        mock_sr.assert_has_calls([
            mock.call('/protocols/cifs/shares', 'get', query=query),
            mock.call(f'/protocols/cifs/shares/{svm_uuid}/{fake.SHARE_NAME}/'
                      'acls', 'get', query=query_acls)
        ])
        self.assertEqual(expected, result)

    @ddt.data((netapp_api.EREST_LICENSE_NOT_INSTALLED, False),
              (netapp_api.EREST_SNAPSHOT_NOT_SPECIFIED, True))
    @ddt.unpack
    def test_check_snaprestore_license(self, code, expected):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error(code)))
        result = self.client.check_snaprestore_license()
        self.assertEqual(expected, result)
        body = {
            'restore_to.snapshot.name': ''
        }
        query = {
            'name': '*'
        }
        self.client.send_request.assert_called_once_with('/storage/volumes',
                                                         'patch',
                                                         body=body,
                                                         query=query)

    def test_check_snaprestore_license_error(self):
        self.mock_object(self.client, 'send_request')
        self.assertRaises(exception.NetAppException,
                          self.client.check_snaprestore_license)

    def test__sort_data_ports_by_speed(self):
        ports = fake.FAKE_PORTS
        result = self.client._sort_data_ports_by_speed(ports)
        expected = [{'speed': '4'},
                    {'speed': 'auto'},
                    {'speed': 'undef'},
                    {'speed': 'fake_speed'},
                    {'speed': ''}]
        self.assertEqual(expected, result)

    def test_create_port_and_broadcast_domain(self):
        self.mock_object(self.client, '_create_vlan')
        self.mock_object(self.client, '_ensure_broadcast_domain_for_port')
        res = self.client.create_port_and_broadcast_domain(fake.NODE_NAME,
                                                           fake.PORT,
                                                           fake.VLAN,
                                                           fake.MTU,
                                                           fake.IPSPACE_NAME)
        expected = f'{fake.PORT}-{fake.VLAN}'
        self.assertEqual(expected, res)

    @ddt.data(netapp_api.EREST_DUPLICATE_ENTRY, None)
    def test__create_vlan(self, code):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error(code)))
        if not code:
            self.assertRaises(exception.NetAppException,
                              self.client._create_vlan,
                              fake.NODE_NAME,
                              fake.PORT,
                              fake.VLAN)

        else:
            self.client._create_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)
            body = {
                'vlan.base_port.name': fake.PORT,
                'node.name': fake.NODE_NAME,
                'vlan.tag': fake.VLAN,
                'type': 'vlan'
            }
            self.client.send_request.assert_called_once_with(
                '/network/ethernet/ports', 'post', body=body)

    @ddt.data(netapp_api.EREST_ENTRY_NOT_FOUND, None)
    def test_delete_fpolicy_event_error_not_found(self, code):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error(code)))
        if not code:
            self.assertRaises(exception.NetAppException,
                              self.client.delete_fpolicy_event,
                              fake.SHARE_NAME, 'fake_event')
        else:
            self.client.delete_fpolicy_event(fake.SHARE_NAME, 'fake_event')
            self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)

    @ddt.data(netapp_api.EREST_ENTRY_NOT_FOUND, None)
    def test_delete_fpolicy_policy_request_error(self, code):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error(code)))
        if not code:
            self.assertRaises(exception.NetAppException,
                              self.client.delete_fpolicy_policy,
                              fake.SHARE_NAME, 'fake_policy')
        else:
            self.client.delete_fpolicy_policy(fake.SHARE_NAME, 'fake_policy')
            self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)

    def test_modify_fpolicy_scope(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        svm_uuid = volume['svm']['uuid']
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        mock_sr = self.mock_object(self.client, 'send_request')
        body = {
            'name': fake.FPOLICY_POLICY_NAME,
            'scope.include_shares': fake.SHARE_NAME,
            'scope.include_extension': 'fake_extension',
            'scope.exclude_extension': 'fake_extension'
        }
        self.client.modify_fpolicy_scope(fake.SHARE_NAME,
                                         fake.FPOLICY_POLICY_NAME,
                                         [fake.SHARE_NAME],
                                         ['fake_extension'],
                                         ['fake_extension'])
        mock_sr.assert_called_once_with(f'/protocols/fpolicy/{svm_uuid}/'
                                        'policies/', 'patch', body=body)

    def test_remove_cifs_share(self):
        response = fake.SVMS_LIST_SIMPLE_RESPONSE_REST
        svm_id = response.get('records')[0]['uuid']
        mock_sr = self.mock_object(self.client, 'send_request',
                                   mock.Mock(return_value=response))
        self.client.remove_cifs_share(fake.SHARE_NAME)
        query = {
            'name': self.client.vserver,
            'fields': 'uuid'
        }
        mock_sr.assert_has_calls([
            mock.call('/svm/svms', 'get', query=query),
            mock.call(f'/protocols/cifs/shares/{svm_id}'
                      f'/{fake.SHARE_NAME}', 'delete')])

    def test_qos_policy_group_get_error(self):
        code = netapp_api.EREST_NOT_AUTHORIZED
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error(code)))
        self.assertRaises(exception.NetAppException,
                          self.client.qos_policy_group_get_legacy,
                          fake.QOS_POLICY_GROUP_NAME)

    def test_qos_policy_group_get_not_found(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(exception.NetAppException,
                          self.client.qos_policy_group_get_legacy,
                          fake.QOS_POLICY_GROUP_NAME)

    def test_remove_unused_qos_policy_groups_error(self):
        res_list = [fake.QOS_POLICY_GROUP_REST, netapp_api.api.NaApiError]
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=res_list))
        self.client.remove_unused_qos_policy_groups()
        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)

    def test_mount_volume_error(self):
        volume = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        code = netapp_api.EREST_SNAPMIRROR_INITIALIZING
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(return_value=volume))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error(code)))
        self.assertRaises(netapp_api.api.NaApiError,
                          self.client.mount_volume,
                          fake.VOLUME_NAMES[0])

    def test_get_aggregate_for_volume_empty(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(exception.NetAppException,
                          self.client.get_aggregate_for_volume,
                          fake.VOLUME_NAMES[0])

    def test_get_nfs_export_policy_for_volume_empty(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=False))
        self.assertRaises(exception.NetAppException,
                          self.client.get_nfs_export_policy_for_volume,
                          fake.VOLUME_NAMES[0])

    def test_get_unique_export_policy_id_empty(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=False))
        self.assertRaises(exception.NetAppException,
                          self.client.get_unique_export_policy_id,
                          fake.FPOLICY_POLICY_NAME)

    def test__remove_nfs_export_rules_error(self):
        self.mock_object(self.client, 'get_unique_export_policy_id',
                         mock.Mock(return_value=fake.FAKE_UUID))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.assertRaises(netapp_api.api.NaApiError,
                          self.client._remove_nfs_export_rules,
                          fake.FPOLICY_POLICY_NAME,
                          [1])

    def test_get_volume_move_status_error(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=False))
        self.assertRaises(exception.NetAppException,
                          self.client.get_volume_move_status,
                          fake.VOLUME_NAMES[0],
                          fake.VSERVER_NAME)

    def test__set_snapmirror_state_error(self):
        self.mock_object(self.client, 'get_snapmirrors',
                         mock.Mock(return_value=[]))
        self.assertRaises(netapp_utils.NetAppDriverException,
                          self.client._set_snapmirror_state,
                          'fake_state', 'fake_source_path', 'fake_dest_path',
                          'fake_source_vserver', 'fake_source_volume',
                          'fake_dest_vserver', 'fake_dest_volume')

    def test__break_snapmirror_error(self):
        fake_snapmirror = fake.REST_GET_SNAPMIRRORS_RESPONSE
        self.mock_object(self.client, '_get_snapmirrors',
                         mock.Mock(return_value=fake_snapmirror))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.assertRaises(netapp_api.api.NaApiError,
                          self.client._break_snapmirror)

    def test__resync_snapmirror_no_parameter(self):
        mock_snap = self.mock_object(self.client, '_resume_snapmirror')
        self.client._resync_snapmirror()
        mock_snap.assert_called_once_with(None, None, None, None, None, None)

    def test_add_nfs_export_rule_with_rule_created(self):
        self.mock_object(self.client, '_get_nfs_export_rule_indices',
                         mock.Mock(return_value=[1]))
        update = self.mock_object(self.client, '_update_nfs_export_rule')
        remove = self.mock_object(self.client, '_remove_nfs_export_rules')
        self.client.add_nfs_export_rule(fake.FPOLICY_POLICY_NAME,
                                        'fake_client',
                                        True,
                                        'fake_auth')
        update.assert_called_once_with(fake.FPOLICY_POLICY_NAME,
                                       'fake_client', True, 1, 'fake_auth',
                                       anon_user_id=None)
        remove.assert_called_once_with(fake.FPOLICY_POLICY_NAME, [])

    def test__update_snapmirror_no_snapmirrors(self):
        self.mock_object(self.client, '_get_snapmirrors',
                         mock.Mock(return_value=[]))
        self.assertRaises(netapp_utils.NetAppDriverException,
                          self.client._update_snapmirror)

    @ddt.data((netapp_api.EREST_SNAPMIRROR_NOT_INITIALIZED,
               'Another transfer is in progress'),
              (None, 'fake'))
    @ddt.unpack
    def test__update_snapmirror_error(self, code, message):
        snapmirrors = fake.REST_GET_SNAPMIRRORS_RESPONSE
        self.mock_object(self.client, '_get_snapmirrors',
                         mock.Mock(return_value=snapmirrors))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error(code,
                                                                    message)))
        self.assertRaises(netapp_api.api.NaApiError,
                          self.client._update_snapmirror)

    @ddt.data(netapp_api.EREST_DUPLICATE_ENTRY, None)
    def test_create_kerberos_realm_error(self, code):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error(code)))
        if code:
            self.client.create_kerberos_realm(fake.KERBEROS_SECURITY_SERVICE)
            self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)
        else:
            self.assertRaises(exception.NetAppException,
                              self.client.create_kerberos_realm,
                              fake.KERBEROS_SECURITY_SERVICE)

    def test_configure_kerberos_error(self):
        self.mock_object(self.client, 'configure_dns')
        self.mock_object(self.client, '_get_kerberos_service_principal_name')
        self.mock_object(self.client, 'get_network_interfaces',
                         mock.Mock(return_value=[]))
        self.assertRaises(exception.NetAppException,
                          self.client.configure_kerberos,
                          fake.KERBEROS_SECURITY_SERVICE,
                          fake.VSERVER_NAME)

    def test_configure_ldap(self):
        mock_ldap = self.mock_object(self.client, '_create_ldap_client')
        self.client.configure_ldap(fake.LDAP_AD_SECURITY_SERVICE, 30,
                                   fake.VSERVER_NAME)
        mock_ldap.assert_called_once_with(fake.LDAP_AD_SECURITY_SERVICE,
                                          vserver_name=fake.VSERVER_NAME)

    def test_configure_active_directory_error(self):
        self.mock_object(self.client, 'configure_dns')
        self.mock_object(self.client, 'configure_cifs_aes_encryption')
        self.mock_object(self.client, 'set_preferred_dc')
        self.mock_object(self.client, '_get_cifs_server_name')
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.assertRaises(exception.NetAppException,
                          self.client.configure_active_directory,
                          fake.LDAP_AD_SECURITY_SERVICE,
                          fake.VSERVER_NAME,
                          False,
                          False)

    def test__get_unique_svm_by_name_error(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(exception.NetAppException,
                          self.client._get_unique_svm_by_name,
                          fake.VSERVER_NAME)

    def test_get_ontap_version_scoped(self):
        self.client.get_ontap_version = self.original_get_ontap_version
        e = netapp_api.api.NaApiError(code=netapp_api.EREST_NOT_AUTHORIZED)
        res_list = [e, fake.GET_VERSION_RESPONSE_REST]
        version = fake.GET_VERSION_RESPONSE_REST['records'][0]['version']
        expected = {
            'version': version['full'],
            'version-tuple': (9, 11, 1)
        }
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=res_list))
        result = self.client.get_ontap_version(self=self.client, cached=False)
        self.assertEqual(expected, result)

    def test_get_licenses_error(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.assertRaises(netapp_api.api.NaApiError,
                          self.client.get_licenses)

    def test__get_volume_by_args_error(self):
        res = fake.VOLUME_GET_ITER_RESPONSE_REST_PAGE
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=res))
        self.assertRaises(exception.NetAppException,
                          self.client._get_volume_by_args,
                          is_root=True)

    def test_get_aggregate_no_name(self):
        expected = {}
        result = self.client.get_aggregate('')
        self.assertEqual(expected, result)

    def test_get_aggregate_error(self):
        self.mock_object(self.client, '_get_aggregates',
                         mock.Mock(side_effect=self._mock_api_error()))
        result = self.client.get_aggregate(fake.SHARE_AGGREGATE_NAME)
        expected = {}
        self.assertEqual(expected, result)

    def test_get_node_for_aggregate_no_name(self):
        result = self.client.get_node_for_aggregate('')
        self.assertIsNone(result)

    @ddt.data(netapp_api.EREST_NOT_AUTHORIZED, None)
    def test_get_node_for_aggregate_error(self, code):
        self.mock_object(self.client, '_get_aggregates',
                         mock.Mock(side_effect=self._mock_api_error(code)))
        if code:
            r = self.client.get_node_for_aggregate(fake.SHARE_AGGREGATE_NAME)
            self.assertIsNone(r)
        else:
            self.assertRaises(netapp_api.api.NaApiError,
                              self.client.get_node_for_aggregate,
                              fake.SHARE_AGGREGATE_NAME)

    def test_get_vserver_aggregate_capabilities_no_response(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(exception.NetAppException,
                          self.client.get_vserver_aggregate_capacities,
                          fake.SHARE_AGGREGATE_NAME)

    def test_get_vserver_aggregate_capacities_no_aggregate(self):
        response = fake.FAKE_AGGREGATES_RESPONSE
        share_name = fake.SHARE_AGGREGATE_NAME
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=response))
        res = self.client.get_vserver_aggregate_capacities(share_name)
        expected = {}
        self.assertEqual(expected, res)

    def test_rename_nfs_export_policy_error(self):
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=False))
        self.assertRaises(exception.NetAppException,
                          self.client.rename_nfs_export_policy,
                          'fake_policy_name',
                          'fake_new_policy_name')

    @ddt.data((False, exception.StorageResourceNotFound),
              (True, exception.NetAppException))
    @ddt.unpack
    def test_get_volume_error(self, records, exception):
        res = copy.deepcopy(fake.FAKE_VOLUME_MANAGE)
        res['num_records'] = 2
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=res))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=records))
        self.assertRaises(exception,
                          self.client.get_volume,
                          fake.VOLUME_NAMES[0])

    def test_get_volume_no_aggregate(self):
        res = copy.deepcopy(fake.FAKE_VOLUME_MANAGE)
        res.get('records')[0]['aggregates'] = []
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=res))
        fake_volume = res.get('records', [])[0]

        expected = {
            'aggregate': '',
            'aggr-list': [],
            'junction-path': fake_volume.get('nas', {}).get('path', ''),
            'name': fake_volume.get('name', ''),
            'owning-vserver-name': fake_volume.get('svm', {}).get('name', ''),
            'type': fake_volume.get('type', ''),
            'style': fake_volume.get('style', ''),
            'size': fake_volume.get('space', {}).get('size', ''),
            'size-used': fake_volume.get('space', {}).get('used', ''),
            'qos-policy-group-name': fake_volume.get('qos', {})
            .get('policy', {})
            .get('name', ''),
            'style-extended': fake_volume.get('style', ''),
            'snaplock-type': fake_volume.get('snaplock', {}).get('type', '')
        }
        result = self.client.get_volume(fake.VOLUME_NAMES[0])
        self.assertEqual(expected, result)

    def test_get_job_state_error(self):
        response = {
            'records': [fake.JOB_SUCCESSFUL_REST,
                        fake.JOB_SUCCESSFUL_REST]
        }
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        self.assertRaises(exception.NetAppException,
                          self.client.get_job_state,
                          fake.JOB_ID)

    def test_get_volume_efficiency_status_error(self):
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.client.get_volume_efficiency_status(fake.VOLUME_NAMES[0])
        self.assertEqual(1, client_cmode_rest.LOG.error.call_count)

    def test_get_fpolicy_scopes_not_found(self):
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(side_effect=exception.NetAppException))
        result = self.client.get_fpolicy_scopes(fake.SHARE_NAME)
        expected = []
        self.assertEqual(expected, result)

    def test_delete_fpolicy_policy_error(self):
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(side_effect=exception.NetAppException))
        self.mock_object(self.client, 'send_request')
        res = self.client.delete_fpolicy_policy(fake.SHARE_NAME,
                                                fake.FPOLICY_POLICY_NAME)
        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)
        self.assertIsNone(res)

    def test_delete_fpolicy_event_error(self):
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(side_effect=exception.NetAppException))
        self.mock_object(self.client, 'send_request')
        res = self.client.delete_fpolicy_event(fake.SHARE_NAME,
                                               fake.FPOLICY_EVENT_NAME)
        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)
        self.assertIsNone(res)

    def test_delete_nfs_export_policy_no_records(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        res = self.client.delete_nfs_export_policy(fake.FPOLICY_POLICY_NAME)
        self.assertIsNone(res)

    def test_remove_cifs_share_not_found(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(exception.NetAppException,
                          self.client.remove_cifs_share,
                          fake.SHARE_NAME)

    @ddt.data(netapp_api.EREST_ENTRY_NOT_FOUND, None)
    def test_remove_cifs_share_error(self, code):
        responses = [fake.SVMS_LIST_SIMPLE_RESPONSE_REST,
                     netapp_api.api.NaApiError(code=code)]
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=responses))
        if not code:
            self.assertRaises(netapp_api.api.NaApiError,
                              self.client.remove_cifs_share,
                              fake.SHARE_NAME)
        else:
            result = self.client.remove_cifs_share(fake.SHARE_NAME)
            self.assertIsNone(result)

    def test_qos_policy_group_does_not_exists(self):
        self.mock_object(self.client, 'qos_policy_group_get_legacy',
                         mock.Mock(side_effect=exception.NetAppException))
        result = self.client.qos_policy_group_exists(fake.QOS_POLICY_GROUP)
        self.assertFalse(result)

    def test_qos_policy_group_rename_error(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(exception.NetAppException,
                          self.client.qos_policy_group_rename,
                          fake.QOS_POLICY_GROUP_NAME,
                          'fake_new_qos_policy_group_name')

    def test_qos_policy_group_rename_same_name(self):
        res = self.client.qos_policy_group_rename(fake.QOS_POLICY_GROUP_NAME,
                                                  fake.QOS_POLICY_GROUP_NAME)
        self.assertIsNone(res)

    def test_qos_policy_group_modify_legacy_error(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(exception.NetAppException,
                          self.client.qos_policy_group_modify_legacy,
                          fake.QOS_POLICY_GROUP_NAME,
                          fake.QOS_MAX_THROUGHPUT,
                          fake.QOS_MIN_THROUGHPUT)

    def test_update_kerberos_realm_error(self):
        self.mock_object(self.client,
                         '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.assertRaises(exception.NetAppException,
                          self.client.update_kerberos_realm,
                          fake.KERBEROS_SECURITY_SERVICE)

    @ddt.data(('fake_domain', 'fake_server'), (None, None))
    @ddt.unpack
    def test_modify_ldap_error(self, domain, server):
        security_service = {
            'domain': domain,
            'server': server,
            'user': 'fake_user',
            'ou': 'fake_ou',
            'dns_ip': 'fake_ip',
            'password': 'fake_password'
        }
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        self.mock_object(self.client, 'send_request')
        self.assertRaises(exception.NetAppException,
                          self.client.modify_ldap,
                          security_service,
                          fake.LDAP_AD_SECURITY_SERVICE)

    def test_update_dns_configuration_error(self):
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        dns_config = {
            'domains': [fake.KERBEROS_SECURITY_SERVICE['domain']],
            'dns-ips': [fake.KERBEROS_SECURITY_SERVICE['dns_ip']],
        }
        self.mock_object(self.client, 'get_dns_config',
                         mock.Mock(return_value=dns_config))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.assertRaises(exception.NetAppException,
                          self.client.update_dns_configuration,
                          ['fake_ips'], ['fake_domain'])

    def test_remove_preferred_dcs_error(self):
        fake_response = [fake.PREFERRED_DC_REST,
                         netapp_api.api.NaApiError]
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=fake_response))
        self.assertRaises(exception.NetAppException,
                          self.client.remove_preferred_dcs,
                          fake.LDAP_AD_SECURITY_SERVICE,
                          fake.FAKE_UUID)

    def test_set_preferred_dc_error(self):
        security = copy.deepcopy(fake.LDAP_AD_SECURITY_SERVICE)
        security['server'] = 'fake_server'
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=fake.FAKE_UUID))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=self._mock_api_error()))
        self.assertRaises(exception.NetAppException,
                          self.client.set_preferred_dc,
                          security,
                          fake.VSERVER_NAME)

    def test_set_preferred_dc_no_server(self):
        result = self.client.set_preferred_dc(fake.LDAP_AD_SECURITY_SERVICE,
                                              fake.VSERVER_NAME)
        self.assertIsNone(result)

    def test__get_svm_peer_uuid_error(self):
        response = fake.NO_RECORDS_RESPONSE_REST
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=response))
        self.assertRaises(exception.NetAppException,
                          self.client._get_svm_peer_uuid,
                          fake.VSERVER_NAME,
                          fake.VSERVER_PEER_NAME)

    def test_create_vserver_dp_destination(self):
        mock_vserver = self.mock_object(self.client, '_create_vserver')
        self.client.create_vserver_dp_destination(fake.VSERVER_NAME,
                                                  fake.FAKE_AGGR_LIST,
                                                  fake.IPSPACE_NAME,
                                                  fake.DELETE_RETENTION_HOURS)
        mock_vserver.assert_called_once_with(fake.VSERVER_NAME,
                                             fake.FAKE_AGGR_LIST,
                                             fake.IPSPACE_NAME,
                                             fake.DELETE_RETENTION_HOURS,
                                             subtype='dp_destination')

    @ddt.data(':', '.')
    def test_create_route_no_destination(self, gateway):
        mock_sr = self.mock_object(self.client, 'send_request')
        body = {
            'gateway': gateway,
            'destination.address': ('::' if netutils.is_valid_ipv6(gateway)
                                    else '0.0.0.0'),
            'destination.netmask': '0'
        }
        self.client.create_route(gateway)
        mock_sr.assert_called_once_with('/network/ip/routes', 'post',
                                        body=body)

    def test_list_root_aggregates(self):
        return_value = fake.FAKE_ROOT_AGGREGATES_RESPONSE
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=return_value))

        result = self.client.list_root_aggregates()

        expected = [fake.SHARE_AGGREGATE_NAME]
        self.assertEqual(expected, result)

    @ddt.data(("fake_server", "fake_domain"), (None, None))
    @ddt.unpack
    def test__create_ldap_client_error(self, server, domain):
        security_service = {
            'server': server,
            'domain': domain,
            'user': 'fake_user',
            'ou': 'fake_ou',
            'dns_ip': 'fake_ip',
            'password': 'fake_password'
        }

        self.assertRaises(exception.NetAppException,
                          self.client._create_ldap_client,
                          security_service)

    @ddt.data(["password"], ["user"])
    def test__modify_active_directory_security_service_error(self, keys):
        svm_uuid = fake.FAKE_UUID
        user_records = fake.FAKE_CIFS_LOCAL_USER.get('records')[0]
        self.mock_object(self.client, '_get_unique_svm_by_name',
                         mock.Mock(return_value=svm_uuid))
        self.mock_object(self.client, 'send_request',
                         mock.Mock(side_effect=[user_records,
                                                netapp_api.api.NaApiError]))
        self.mock_object(self.client, 'remove_preferred_dcs')
        self.mock_object(self.client, 'set_preferred_dc')
        new_security_service = {
            'user': 'new_user',
            'password': 'new_password',
            'server': 'fake_server'
        }

        current_security_service = {
            'server': 'fake_current_server'
        }

        self.assertRaises(
            exception.NetAppException,
            self.client.modify_active_directory_security_service,
            fake.VSERVER_NAME,
            keys,
            new_security_service,
            current_security_service)

    def test_disable_kerberos_error(self):
        fake_api_response = fake.NFS_LIFS_REST
        api_error = self._mock_api_error()
        self.mock_object(self.client, 'get_network_interfaces',
                         mock.Mock(return_value=fake_api_response))
        self.mock_object(
            self.client, 'send_request',
            mock.Mock(side_effect=api_error))

        self.assertRaises(exception.NetAppException,
                          self.client.disable_kerberos,
                          fake.LDAP_AD_SECURITY_SERVICE)

    def test_set_volume_snapdir_access_exception(self):
        fake_hide_snapdir = 'fake-snapdir'

        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(side_effect=exception.NetAppException))
        self.assertRaises(exception.SnapshotResourceNotFound,
                          self.client.set_volume_snapdir_access,
                          fake.VOLUME_NAMES[0],
                          fake_hide_snapdir)

    def test__get_broadcast_domain_for_port_exception(self):
        fake_response_empty = {
            "records": [{}]
        }
        self.mock_object(self.client, 'send_request', mock.Mock(
            return_value=fake_response_empty))

        self.assertRaises(exception.NetAppException,
                          self.client._get_broadcast_domain_for_port,
                          fake.NODE_NAME,
                          fake.PORT)

    def test__configure_nfs_exception(self):
        fake_nfs = {
            'udp-max-xfer-size': 10000,
            'tcp-max-xfer-size': 10000,
        }
        self.assertRaises(exception.NetAppException,
                          self.client._configure_nfs,
                          fake_nfs,
                          fake.FAKE_UUID)

    def test_get_snapshot_exception(self):
        self.mock_object(self.client, '_get_volume_by_args',
                         mock.Mock(side_effect=exception.NetAppException))
        self.assertRaises(exception.SnapshotResourceNotFound,
                          self.client.get_snapshot,
                          fake.VOLUME_NAMES[0],
                          fake.SNAPSHOT_NAME)

    def test_delete_snapshot_exception(self):
        self.mock_object(self.client,
                         '_get_volume_by_args',
                         mock.Mock(side_effect=exception.NetAppException))
        self.client.delete_snapshot(fake.VOLUME_NAMES[0], fake.SNAPSHOT_NAME,
                                    True)

        self.assertEqual(1, client_cmode_rest.LOG.warning.call_count)

    def test_set_nfs_export_policy_for_volume_exception(self):
        return_code = netapp_api.EREST_CANNOT_MODITY_OFFLINE_VOLUME
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(side_effect=self._mock_api_error(
                             code=return_code)))
        self.client.set_nfs_export_policy_for_volume(
            fake.VOLUME_NAMES[0], fake.EXPORT_POLICY_NAME)

        self.assertEqual(1, client_cmode_rest.LOG.debug.call_count)

    def test__break_snapmirror_exception(self):
        fake_snapmirror = copy.deepcopy(fake.REST_GET_SNAPMIRRORS_RESPONSE)
        fake_snapmirror[0]['transferring-state'] = 'error'

        self.mock_object(
            self.client, '_get_snapmirrors',
            mock.Mock(return_value=fake_snapmirror))

        self.assertRaises(netapp_utils.NetAppDriverException,
                          self.client._break_snapmirror)

    def test_get_svm_volumes_total_size(self):
        expected = 1

        fake_query = {
            'svm.name': fake.VSERVER_NAME,
            'fields': 'size'
        }

        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake.FAKE_GET_VOLUME))

        result = self.client.get_svm_volumes_total_size(fake.VSERVER_NAME)

        self.client.send_request.assert_called_once_with(
            '/storage/volumes/', 'get', query=fake_query)

        self.assertEqual(expected, result)

    @ddt.data(fake.CIFS_SECURITY_SERVICE, fake.CIFS_SECURITY_SERVICE_3)
    def test_configure_active_directory_credential_error(self,
                                                         security_service):
        msg = "could not authenticate"
        fake_security = copy.deepcopy(security_service)

        self.mock_object(self.client, 'configure_dns')
        self.mock_object(self.client, 'set_preferred_dc')
        self.mock_object(self.client, 'configure_cifs_aes_encryption')
        self.mock_object(self.client, '_get_cifs_server_name')
        self.mock_object(self.client, 'send_request',
                         self._mock_api_error(code=netapp_api.api.EAPIERROR,
                                              message=msg))
        self.assertRaises(exception.SecurityServiceFailedAuth,
                          self.client.configure_active_directory,
                          fake_security,
                          fake.VSERVER_NAME,
                          False,
                          False)

    @ddt.data(fake.CIFS_SECURITY_SERVICE, fake.CIFS_SECURITY_SERVICE_3)
    def test_configure_active_directory_user_privilege_error(self,
                                                             security_service):
        msg = "insufficient access"
        fake_security = copy.deepcopy(security_service)

        self.mock_object(self.client, 'configure_dns')
        self.mock_object(self.client, 'set_preferred_dc')
        self.mock_object(self.client, 'configure_cifs_aes_encryption')
        self.mock_object(self.client, '_get_cifs_server_name')
        self.mock_object(self.client, 'send_request',
                         self._mock_api_error(code=netapp_api.api.EAPIERROR,
                                              message=msg))
        self.assertRaises(exception.SecurityServiceFailedAuth,
                          self.client.configure_active_directory,
                          fake_security,
                          fake.VSERVER_NAME,
                          False,
                          False)

    def test_snapmirror_restore_vol(self):
        uuid = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST["uuid"]
        body = {
            "destination": {"path": fake.SM_DEST_PATH,
                            "cluster": {"name": fake.CLUSTER_NAME}},
            "source_snapshot": fake.SNAPSHOT_NAME
        }
        snapmirror_info = [{'destination-vserver': "fake_des_vserver",
                            'destination-volume': "fake_des_vol",
                            'relationship-status': "idle",
                            'uuid': uuid}]

        self.mock_object(self.client, 'get_snapmirrors',
                         mock.Mock(return_value=snapmirror_info))
        self.mock_object(self.client, 'send_request')
        self.client.snapmirror_restore_vol(source_path=fake.SM_SOURCE_PATH,
                                           dest_path=fake.SM_DEST_PATH,
                                           source_snapshot=fake.SNAPSHOT_NAME,
                                           des_cluster=fake.CLUSTER_NAME)
        self.client.send_request.assert_called_once_with(
            f'/snapmirror/relationships/{uuid}/restore', 'post', body=body)

    @ddt.data({'snapmirror_label': None, 'newer_than': '2345'},
              {'snapmirror_label': "fake_backup", 'newer_than': None})
    @ddt.unpack
    def test_list_volume_snapshots(self, snapmirror_label, newer_than):
        fake_response = fake.SNAPSHOTS_REST_RESPONSE
        api_response = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST
        self.mock_object(self.client,
                         '_get_volume_by_args',
                         mock.Mock(return_value=api_response))
        mock_request = self.mock_object(self.client, 'send_request',
                                        mock.Mock(return_value=fake_response))
        self.client.list_volume_snapshots(fake.SHARE_NAME,
                                          snapmirror_label=snapmirror_label,
                                          newer_than=newer_than)
        uuid = fake.VOLUME_ITEM_SIMPLE_RESPONSE_REST["uuid"]
        query = {}
        if snapmirror_label:
            query = {
                'snapmirror_label': snapmirror_label,
            }
        if newer_than:
            query['create_time'] = '>' + newer_than

        mock_request.assert_called_once_with(
            f'/storage/volumes/{uuid}/snapshots/',
            'get', query=query)

    @ddt.data(('vault', False, True), (None, False, False))
    @ddt.unpack
    def test_create_snapmirror_policy_rest(self, policy_type,
                                           discard_network_info,
                                           preserve_snapshots):
        fake_response = fake.SNAPSHOTS_REST_RESPONSE
        self.mock_object(self.client, 'send_request',
                         mock.Mock(return_value=fake_response))
        policy_name = fake.SNAPMIRROR_POLICY_NAME
        self.client.create_snapmirror_policy(
            policy_name, policy_type=policy_type,
            discard_network_info=discard_network_info,
            preserve_snapshots=preserve_snapshots,
            snapmirror_label='backup',
            keep=30)
        if policy_type == "vault":
            body = {"name": policy_name, "type": "async",
                    "create_snapshot_on_source": False}
        else:
            body = {"name": policy_name, "type": policy_type}
        if discard_network_info:
            body["exclude_network_config"] = {'svmdr-config-obj': 'network'}
        if preserve_snapshots:
            body["retention"] = [{"label": 'backup', "count": 30}]
        self.client.send_request.assert_called_once_with(
            '/snapmirror/policies/', 'post', body=body)

    def test_is_snaplock_compliance_clock_configured(self):
        self.mock_object(self.client,
                         '_get_cluster_node_uuid',
                         mock.Mock(return_value="uuid"))
        api_response = {'time': 'Thu Aug 08 00:51:30 EDT 2024 -04:00'}
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))
        result = self.client.is_snaplock_compliance_clock_configured(
            "test_node"
        )
        self.assertIs(True, result)

    def test_is_snaplock_compliance_clock_configured_negative(self):
        self.mock_object(self.client,
                         '_get_cluster_node_uuid',
                         mock.Mock(return_value="uuid"))
        api_response = {'time': None}
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=api_response))
        result = self.client.is_snaplock_compliance_clock_configured(
            "test_node"
        )
        self.assertIs(False, result)

    @ddt.data({'options': {'snaplock_autocommit_period': "4hours",
                           'snaplock_min_retention_period': "6days",
                           'snaplock_max_retention_period': "8months",
                           'snaplock_default_retention_period': "8days"},
               },
              {'options': {'snaplock_autocommit_period': "4hours",
                           'snaplock_min_retention_period': "6days",
                           'snaplock_max_retention_period': "8months",
                           'snaplock_default_retention_period': "min"},
               },
              {'options': {'snaplock_autocommit_period': "4hours",
                           'snaplock_min_retention_period': "6days",
                           'snaplock_max_retention_period': "8months",
                           'snaplock_default_retention_period': "max"},
               },
              )
    @ddt.unpack
    def test_set_snaplock_attributes(self, options):
        self.mock_object(self.client, 'send_request')

        body = {
            'snaplock.autocommit_period':
                utils.convert_time_duration_to_iso_format(
                    options.get('snaplock_autocommit_period')),
            'snaplock.retention.minimum':
                utils.convert_time_duration_to_iso_format(
                    options.get('snaplock_min_retention_period')),
            'snaplock.retention.maximum':
                utils.convert_time_duration_to_iso_format(
                    options.get('snaplock_max_retention_period')),
        }
        if options.get('snaplock_default_retention_period') == "min":
            body['snaplock.retention.default'] = (
                utils.convert_time_duration_to_iso_format(
                    options.get('snaplock_min_retention_period'))
            )
        elif options.get('snaplock_default_retention_period') == 'max':
            body['snaplock.retention.default'] = (
                utils.convert_time_duration_to_iso_format(
                    options.get('snaplock_max_retention_period'))
            )
        else:
            body['snaplock.retention.default'] = (
                utils.convert_time_duration_to_iso_format(
                    options.get('snaplock_default_retention_period'))
            )

        self.mock_object(self.client,
                         '_get_volume_by_args',
                         mock.Mock(return_value={'uuid': fake.FAKE_UUID}))
        self.client.set_snaplock_attributes(fake.SHARE_NAME, **options)

        vol_uid = fake.FAKE_UUID
        self.client.send_request.assert_called_once_with(
            f'/storage/volumes/{vol_uid}', 'patch', body=body)

    def test_set_snaplock_attributes_none(self):
        self.mock_object(self.client, 'send_request')
        self.mock_object(self.client,
                         '_get_volume_by_args',
                         mock.Mock(return_value={'uuid': fake.FAKE_UUID}))
        options = {'snaplock_autocommit_period': None,
                   'snaplock_min_retention_period': None,
                   'snaplock_max_retention_period': None,
                   'snaplock_default_retention_period': None,
                   }
        self.client.set_snaplock_attributes(fake.SHARE_NAME, **options)
        self.client.send_request.assert_not_called()

    def test__get_cluster_node_uuid(self):
        response = {'records': [{'uuid': fake.FAKE_UUID}]}
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=response))

        result = self.client._get_cluster_node_uuid("fake_node")
        self.assertEqual(result, fake.FAKE_UUID)

    @ddt.data("compliance", "enterprise")
    def test__is_snaplock_enabled_volume_true(self, snaplock_type):
        vol_attr = {'snaplock-type': snaplock_type}
        self.mock_object(self.client,
                         'get_volume',
                         mock.Mock(return_value=vol_attr))
        result = self.client._is_snaplock_enabled_volume(
            fake.SHARE_AGGREGATE_NAMES
        )
        self.assertIs(True, result)

    def test__is_snaplock_enabled_volume_false(self):
        vol_attr = {'snaplock-type': "non-snaplock"}
        self.mock_object(self.client,
                         'get_volume',
                         mock.Mock(return_value=vol_attr))
        result = self.client._is_snaplock_enabled_volume(
            fake.SHARE_AGGREGATE_NAMES
        )
        self.assertIs(False, result)

    def test_get_storage_failover_partner(self):
        self.mock_object(self.client,
                         '_get_cluster_node_uuid',
                         mock.Mock(return_value=fake.FAKE_UUID))
        response = {'ha': {'partners': [{'name': 'partner_node'}]}}
        self.mock_object(self.client,
                         'send_request',
                         mock.Mock(return_value=response))
        result = self.client.get_storage_failover_partner("fake_node")
        self.assertEqual(result, "partner_node")

    def test_get_migratable_data_lif_for_node(self):
        api_response = fake.GENERIC_NETWORK_INTERFACES_GET_REPONSE
        expected_result = [fake.LIF_NAME]

        self.mock_object(self.client, '_has_records',
                         mock.Mock(return_value=True))
        self.mock_object(
            self.client,
            'send_request',
            mock.Mock(side_effect=self._send_request_side_effect)
        )
        uuid = api_response['records'][0]['uuid']
        result = self.client.get_migratable_data_lif_for_node("fake_node")
        self.client.send_request.assert_any_call(
            '/network/ip/interfaces', 'get',
            query={
                'services': 'data_nfs|data_cifs',
                'location.home_node.name': 'fake_node',
                'fields': 'name',
            }
        )
        self.client.send_request.assert_any_call(
            f'/network/ip/interfaces/{uuid}', 'get'
        )
        self.assertEqual(expected_result, result)

    def _send_request_side_effect(self, endpoint, method, query=None):
        if (endpoint == '/network/ip/interfaces' and method == 'get'
                and query is not None):
            return {"records": [{"uuid": "fake_uuid", "name": fake.LIF_NAME}]}
        elif (endpoint.startswith('/network/ip/interfaces/')
              and method == 'get'):
            return {'location': {'failover': 'sfo_partners_only'}}
        return {}
