# Copyright 2023 RedHat 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 sys
from unittest import mock

import ddt

from glance_store._drivers.cinder import base
from glance_store._drivers.cinder import scaleio
from glance_store.tests import base as test_base

sys.modules['glance_store.common.fs_mount'] = mock.Mock()
from glance_store._drivers.cinder import store as cinder # noqa
from glance_store._drivers.cinder import nfs # noqa


@ddt.ddt
class TestConnectorBase(test_base.StoreBaseTest):
    @ddt.data(
        ('iscsi', base.BaseBrickConnectorInterface),
        ('nfs', nfs.NfsBrickConnector),
        ('scaleio', scaleio.ScaleIOBrickConnector),
    )
    @ddt.unpack
    def test_factory(self, protocol, expected_class):
        connector_class = base.factory(
            connection_info={'driver_volume_type': protocol})
        self.assertTrue(isinstance(connector_class, expected_class))


class TestBaseBrickConnectorInterface(test_base.StoreBaseTest):

    def get_connection_info(self):
        """Return iSCSI connection information"""
        return {
            'target_discovered': False,
            'target_portal': '0.0.0.0:3260',
            'target_iqn': 'iqn.2010-10.org.openstack:volume-fake-vol',
            'target_lun': 0,
            'volume_id': '007dedb8-ddc0-445c-88f1-d07acbe4efcb',
            'auth_method': 'CHAP',
            'auth_username': '2ttANgVaDRqxtMNK3hUj',
            'auth_password': 'fake-password',
            'encrypted': False,
            'qos_specs': None,
            'access_mode': 'rw',
            'cacheable': False,
            'driver_volume_type': 'iscsi',
            'attachment_id': '7f45b2fe-111a-42df-be3e-f02b312ad8ea'}

    def setUp(self, connection_info={}, **kwargs):
        super().setUp()
        self.connection_info = connection_info or self.get_connection_info()
        self.root_helper = 'fake_rootwrap'
        self.use_multipath = False
        self.properties = {
            'connection_info': self.connection_info,
            'root_helper': self.root_helper,
            'use_multipath': self.use_multipath}
        self.properties.update(kwargs)
        self.mock_object(base.connector.InitiatorConnector, 'factory')
        self.connector = base.factory(**self.properties)

    def mock_object(self, obj, attr_name, *args, **kwargs):
        """Use python mock to mock an object attribute

        Mocks the specified objects attribute with the given value.
        Automatically performs 'addCleanup' for the mock.
        """
        patcher = mock.patch.object(obj, attr_name, *args, **kwargs)
        result = patcher.start()
        self.addCleanup(patcher.stop)
        return result

    def test_connect_volume(self):
        if self.connection_info['driver_volume_type'] == 'nfs':
            self.skip('NFS tests have custom implementation of this method.')
        fake_vol = mock.MagicMock()
        fake_path = {'path': 'fake_dev_path'}
        self.mock_object(self.connector.conn, 'connect_volume',
                         return_value=fake_path)
        fake_dev_path = self.connector.connect_volume(fake_vol)
        self.connector.conn.connect_volume.assert_called_once_with(
            self.connector.connection_info)
        self.assertEqual(fake_path['path'], fake_dev_path['path'])

    def test_disconnect_volume(self):
        fake_device = 'fake_dev_path'
        self.mock_object(self.connector.conn, 'disconnect_volume')
        self.connector.disconnect_volume(fake_device)
        self.connector.conn.disconnect_volume.assert_called_once_with(
            self.connection_info, fake_device)

    def test_extend_volume(self):
        self.mock_object(self.connector.conn, 'extend_volume')
        self.connector.extend_volume()
        self.connector.conn.extend_volume.assert_called_once_with(
            self.connection_info)

    def test_yield_path(self):
        fake_vol = mock.MagicMock()
        fake_device = 'fake_dev_path'
        fake_dev_path = self.connector.yield_path(fake_vol, fake_device)
        self.assertEqual(fake_device, fake_dev_path)
