# Copyright (c) 2016 Hitachi Data Systems, Inc.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import copy
import ddt
import mock

from manila.common import constants
from manila import context
from manila import db
from manila import exception
from manila.share import snapshot_access
from manila import test
from manila.tests import db_utils
from manila import utils


@ddt.ddt
class SnapshotAccessTestCase(test.TestCase):
    def setUp(self):
        super(SnapshotAccessTestCase, self).setUp()
        self.driver = self.mock_class("manila.share.driver.ShareDriver",
                                      mock.Mock())
        self.snapshot_access = snapshot_access.ShareSnapshotInstanceAccess(
            db, self.driver)
        self.context = context.get_admin_context()
        share = db_utils.create_share()
        self.snapshot = db_utils.create_snapshot(share_id=share['id'])
        self.snapshot_instance = db_utils.create_snapshot_instance(
            snapshot_id=self.snapshot['id'],
            share_instance_id=self.snapshot['share']['instance']['id'])

    @ddt.data(constants.ACCESS_STATE_QUEUED_TO_APPLY,
              constants.ACCESS_STATE_QUEUED_TO_DENY)
    def test_update_access_rules(self, state):

        rules = []
        for i in range(2):
            rules.append({
                'id': 'id-%s' % i,
                'state': state,
                'access_id': 'rule_id%s' % i
            })
        all_rules = copy.deepcopy(rules)
        all_rules.append({
            'id': 'id-3',
            'state': constants.ACCESS_STATE_ERROR,
            'access_id': 'rule_id3'
        })

        snapshot_instance_get = self.mock_object(
            db, 'share_snapshot_instance_get',
            mock.Mock(return_value=self.snapshot_instance))

        snap_get_all_for_snap_instance = self.mock_object(
            db, 'share_snapshot_access_get_all_for_snapshot_instance',
            mock.Mock(return_value=all_rules))

        self.mock_object(db, 'share_snapshot_instance_access_update')
        self.mock_object(self.driver, 'snapshot_update_access')
        self.mock_object(self.snapshot_access, '_check_needs_refresh',
                         mock.Mock(return_value=False))
        self.mock_object(db, 'share_snapshot_instance_access_delete')

        self.snapshot_access.update_access_rules(self.context,
                                                 self.snapshot_instance['id'])

        snapshot_instance_get.assert_called_once_with(
            utils.IsAMatcher(context.RequestContext),
            self.snapshot_instance['id'], with_share_data=True)
        snap_get_all_for_snap_instance.assert_called_once_with(
            utils.IsAMatcher(context.RequestContext),
            self.snapshot_instance['id'])
        if state == constants.ACCESS_STATE_QUEUED_TO_APPLY:
            self.driver.snapshot_update_access.assert_called_once_with(
                utils.IsAMatcher(context.RequestContext),
                self.snapshot_instance, rules, add_rules=rules,
                delete_rules=[], share_server=None)
        else:
            self.driver.snapshot_update_access.assert_called_once_with(
                utils.IsAMatcher(context.RequestContext),
                self.snapshot_instance, [], add_rules=[],
                delete_rules=rules, share_server=None)

    def test_update_access_rules_delete_all_rules(self):

        rules = []
        for i in range(2):
            rules.append({
                'id': 'id-%s' % i,
                'state': constants.ACCESS_STATE_QUEUED_TO_DENY,
                'access_id': 'rule_id%s' % i
            })

        snapshot_instance_get = self.mock_object(
            db, 'share_snapshot_instance_get',
            mock.Mock(return_value=self.snapshot_instance))

        snap_get_all_for_snap_instance = self.mock_object(
            db, 'share_snapshot_access_get_all_for_snapshot_instance',
            mock.Mock(side_effect=[rules, []]))

        self.mock_object(db, 'share_snapshot_instance_access_update')
        self.mock_object(self.driver, 'snapshot_update_access')
        self.mock_object(db, 'share_snapshot_instance_access_delete')

        self.snapshot_access.update_access_rules(self.context,
                                                 self.snapshot_instance['id'],
                                                 delete_all_rules=True)

        snapshot_instance_get.assert_called_once_with(
            utils.IsAMatcher(context.RequestContext),
            self.snapshot_instance['id'], with_share_data=True)
        snap_get_all_for_snap_instance.assert_called_with(
            utils.IsAMatcher(context.RequestContext),
            self.snapshot_instance['id'])
        self.driver.snapshot_update_access.assert_called_with(
            utils.IsAMatcher(context.RequestContext), self.snapshot_instance,
            [], add_rules=[], delete_rules=rules, share_server=None)

    def test_update_access_rules_exception(self):

        rules = []
        for i in range(2):
            rules.append({
                'id': 'id-%s' % i,
                'state': constants.ACCESS_STATE_APPLYING,
                'access_id': 'rule_id%s' % i
            })

        snapshot_instance_get = self.mock_object(
            db, 'share_snapshot_instance_get',
            mock.Mock(return_value=self.snapshot_instance))

        snap_get_all_for_snap_instance = self.mock_object(
            db, 'share_snapshot_access_get_all_for_snapshot_instance',
            mock.Mock(return_value=rules))

        self.mock_object(db, 'share_snapshot_instance_access_update')
        self.mock_object(self.driver, 'snapshot_update_access',
                         mock.Mock(side_effect=exception.NotFound))

        self.assertRaises(exception.NotFound,
                          self.snapshot_access.update_access_rules,
                          self.context, self.snapshot_instance['id'])

        snapshot_instance_get.assert_called_once_with(
            utils.IsAMatcher(context.RequestContext),
            self.snapshot_instance['id'], with_share_data=True)
        snap_get_all_for_snap_instance.assert_called_once_with(
            utils.IsAMatcher(context.RequestContext),
            self.snapshot_instance['id'])

        self.driver.snapshot_update_access.assert_called_once_with(
            utils.IsAMatcher(context.RequestContext), self.snapshot_instance,
            rules, add_rules=rules, delete_rules=[], share_server=None)

[((1631, 1723), 'ddt.data', 'ddt.data', (['constants.ACCESS_STATE_QUEUED_TO_APPLY', 'constants.ACCESS_STATE_QUEUED_TO_DENY'], {}), '(constants.ACCESS_STATE_QUEUED_TO_APPLY, constants.\n    ACCESS_STATE_QUEUED_TO_DENY)\n', (1639, 1723), False, 'import ddt\n'), ((1204, 1264), 'manila.share.snapshot_access.ShareSnapshotInstanceAccess', 'snapshot_access.ShareSnapshotInstanceAccess', (['db', 'self.driver'], {}), '(db, self.driver)\n', (1247, 1264), False, 'from manila.share import snapshot_access\n'), ((1301, 1328), 'manila.context.get_admin_context', 'context.get_admin_context', ([], {}), '()\n', (1326, 1328), False, 'from manila import context\n'), ((1345, 1368), 'manila.tests.db_utils.create_share', 'db_utils.create_share', ([], {}), '()\n', (1366, 1368), False, 'from manila.tests import db_utils\n'), ((1393, 1439), 'manila.tests.db_utils.create_snapshot', 'db_utils.create_snapshot', ([], {'share_id': "share['id']"}), "(share_id=share['id'])\n", (1417, 1439), False, 'from manila.tests import db_utils\n'), ((1473, 1603), 'manila.tests.db_utils.create_snapshot_instance', 'db_utils.create_snapshot_instance', ([], {'snapshot_id': "self.snapshot['id']", 'share_instance_id': "self.snapshot['share']['instance']['id']"}), "(snapshot_id=self.snapshot['id'],\n    share_instance_id=self.snapshot['share']['instance']['id'])\n", (1506, 1603), False, 'from manila.tests import db_utils\n'), ((2001, 2021), 'copy.deepcopy', 'copy.deepcopy', (['rules'], {}), '(rules)\n', (2014, 2021), False, 'import copy\n'), ((1160, 1171), 'mock.Mock', 'mock.Mock', ([], {}), '()\n', (1169, 1171), False, 'import mock\n'), ((2283, 2329), 'mock.Mock', 'mock.Mock', ([], {'return_value': 'self.snapshot_instance'}), '(return_value=self.snapshot_instance)\n', (2292, 2329), False, 'import mock\n'), ((2474, 2507), 'mock.Mock', 'mock.Mock', ([], {'return_value': 'all_rules'}), '(return_value=all_rules)\n', (2483, 2507), False, 'import mock\n'), ((2740, 2769), 'mock.Mock', 'mock.Mock', ([], {'return_value': '(False)'}), '(return_value=False)\n', (2749, 2769), False, 'import mock\n'), ((3052, 3092), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (3068, 3092), False, 'from manila import utils\n'), ((3234, 3274), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (3250, 3274), False, 'from manila import utils\n'), ((4282, 4328), 'mock.Mock', 'mock.Mock', ([], {'return_value': 'self.snapshot_instance'}), '(return_value=self.snapshot_instance)\n', (4291, 4328), False, 'import mock\n'), ((4473, 4507), 'mock.Mock', 'mock.Mock', ([], {'side_effect': '[rules, []]'}), '(side_effect=[rules, []])\n', (4482, 4507), False, 'import mock\n'), ((4997, 5037), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (5013, 5037), False, 'from manila import utils\n'), ((5174, 5214), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (5190, 5214), False, 'from manila import utils\n'), ((5333, 5373), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (5349, 5373), False, 'from manila import utils\n'), ((5856, 5902), 'mock.Mock', 'mock.Mock', ([], {'return_value': 'self.snapshot_instance'}), '(return_value=self.snapshot_instance)\n', (5865, 5902), False, 'import mock\n'), ((6047, 6076), 'mock.Mock', 'mock.Mock', ([], {'return_value': 'rules'}), '(return_value=rules)\n', (6056, 6076), False, 'import mock\n'), ((6238, 6279), 'mock.Mock', 'mock.Mock', ([], {'side_effect': 'exception.NotFound'}), '(side_effect=exception.NotFound)\n', (6247, 6279), False, 'import mock\n'), ((6534, 6574), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (6550, 6574), False, 'from manila import utils\n'), ((6716, 6756), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (6732, 6756), False, 'from manila import utils\n'), ((6881, 6921), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (6897, 6921), False, 'from manila import utils\n'), ((3466, 3506), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (3482, 3506), False, 'from manila import utils\n'), ((3726, 3766), 'manila.utils.IsAMatcher', 'utils.IsAMatcher', (['context.RequestContext'], {}), '(context.RequestContext)\n', (3742, 3766), False, 'from manila import utils\n')]