"Fossies" - the Fresh Open Source Software Archive

Member "manila-11.0.1/manila/tests/api/v2/test_shares.py" (1 Feb 2021, 123300 Bytes) of package /linux/misc/openstack/manila-11.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_shares.py": 11.0.0_vs_11.0.1.

    1 # Copyright (c) 2015 Mirantis inc.
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 import copy
   17 import datetime
   18 import itertools
   19 from unittest import mock
   20 
   21 import ddt
   22 from oslo_config import cfg
   23 from oslo_serialization import jsonutils
   24 from oslo_utils import uuidutils
   25 import six
   26 import webob
   27 import webob.exc
   28 
   29 from manila.api import common
   30 from manila.api.openstack import api_version_request as api_version
   31 from manila.api.v2 import share_replicas
   32 from manila.api.v2 import shares
   33 from manila.common import constants
   34 from manila import context
   35 from manila import db
   36 from manila import exception
   37 from manila import policy
   38 from manila.share import api as share_api
   39 from manila.share import share_types
   40 from manila import test
   41 from manila.tests.api.contrib import stubs
   42 from manila.tests.api import fakes
   43 from manila.tests import db_utils
   44 from manila.tests import fake_share
   45 from manila.tests import utils as test_utils
   46 from manila import utils
   47 
   48 CONF = cfg.CONF
   49 
   50 LATEST_MICROVERSION = api_version._MAX_API_VERSION
   51 
   52 
   53 @ddt.ddt
   54 class ShareAPITest(test.TestCase):
   55     """Share API Test."""
   56 
   57     def setUp(self):
   58         super(ShareAPITest, self).setUp()
   59         self.controller = shares.ShareController()
   60         self.mock_object(db, 'availability_zone_get')
   61         self.mock_object(share_api.API, 'get_all',
   62                          stubs.stub_get_all_shares)
   63         self.mock_object(share_api.API, 'get',
   64                          stubs.stub_share_get)
   65         self.mock_object(share_api.API, 'update', stubs.stub_share_update)
   66         self.mock_object(share_api.API, 'delete', stubs.stub_share_delete)
   67         self.mock_object(share_api.API, 'get_snapshot',
   68                          stubs.stub_snapshot_get)
   69         self.mock_object(share_types, 'get_share_type',
   70                          stubs.stub_share_type_get)
   71         self.maxDiff = None
   72         self.share = {
   73             "id": "1",
   74             "size": 100,
   75             "display_name": "Share Test Name",
   76             "display_description": "Share Test Desc",
   77             "share_proto": "fakeproto",
   78             "availability_zone": "zone1:host1",
   79             "is_public": False,
   80             "task_state": None,
   81         }
   82         self.create_mock = mock.Mock(
   83             return_value=stubs.stub_share(
   84                 '1',
   85                 display_name=self.share['display_name'],
   86                 display_description=self.share['display_description'],
   87                 size=100,
   88                 share_proto=self.share['share_proto'].upper(),
   89                 instance={
   90                     'availability_zone': self.share['availability_zone'],
   91                 })
   92         )
   93         self.vt = {
   94             'id': 'fake_volume_type_id',
   95             'name': 'fake_volume_type_name',
   96             'required_extra_specs': {
   97                 'driver_handles_share_servers': 'False'
   98             },
   99             'extra_specs': {
  100                 'driver_handles_share_servers': 'False'
  101             }
  102         }
  103         self.snapshot = {
  104             'id': '2',
  105             'share_id': '1',
  106             'status': constants.STATUS_AVAILABLE,
  107         }
  108 
  109         CONF.set_default("default_share_type", None)
  110 
  111     def _process_expected_share_detailed_response(self, shr_dict, req_version):
  112         """Sets version based parameters on share dictionary."""
  113 
  114         share_dict = copy.deepcopy(shr_dict)
  115         changed_parameters = {
  116             '2.2': {'snapshot_support': True},
  117             '2.5': {'task_state': None},
  118             '2.6': {'share_type_name': None},
  119             '2.10': {'access_rules_status': constants.ACCESS_STATE_ACTIVE},
  120             '2.11': {'replication_type': None, 'has_replicas': False},
  121             '2.16': {'user_id': 'fakeuser'},
  122             '2.24': {'create_share_from_snapshot_support': True},
  123             '2.27': {'revert_to_snapshot_support': False},
  124             '2.31': {'share_group_id': None,
  125                      'source_share_group_snapshot_member_id': None},
  126             '2.32': {'mount_snapshot_support': False},
  127         }
  128 
  129         # Apply all the share transformations
  130         if self.is_microversion_ge(req_version, '2.9'):
  131             share_dict.pop('export_locations', None)
  132             share_dict.pop('export_location', None)
  133 
  134         for version, parameters in changed_parameters.items():
  135             for param, default in parameters.items():
  136                 if self.is_microversion_ge(req_version, version):
  137                     share_dict[param] = share_dict.get(param, default)
  138                 else:
  139                     share_dict.pop(param, None)
  140 
  141         return share_dict
  142 
  143     def _get_expected_share_detailed_response(self, values=None,
  144                                               admin=False, version='2.0'):
  145         share = {
  146             'id': '1',
  147             'name': 'displayname',
  148             'availability_zone': 'fakeaz',
  149             'description': 'displaydesc',
  150             'export_location': 'fake_location',
  151             'export_locations': ['fake_location', 'fake_location2'],
  152             'project_id': 'fakeproject',
  153             'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
  154             'share_proto': 'FAKEPROTO',
  155             'metadata': {},
  156             'size': 1,
  157             'snapshot_id': '2',
  158             'share_network_id': None,
  159             'status': 'fakestatus',
  160             'share_type': '1',
  161             'volume_type': '1',
  162             'snapshot_support': True,
  163             'is_public': False,
  164             'task_state': None,
  165             'share_type_name': None,
  166             'links': [
  167                 {
  168                     'href': 'http://localhost/v1/fake/shares/1',
  169                     'rel': 'self'
  170                 },
  171                 {
  172                     'href': 'http://localhost/fake/shares/1',
  173                     'rel': 'bookmark'
  174                 }
  175             ],
  176         }
  177         if values:
  178             if 'display_name' in values:
  179                 values['name'] = values.pop('display_name')
  180             if 'display_description' in values:
  181                 values['description'] = values.pop('display_description')
  182             share.update(values)
  183         if share.get('share_proto'):
  184             share['share_proto'] = share['share_proto'].upper()
  185         if admin:
  186             share['share_server_id'] = 'fake_share_server_id'
  187             share['host'] = 'fakehost'
  188         return {
  189             'share': self._process_expected_share_detailed_response(
  190                 share, version)
  191         }
  192 
  193     def test__revert(self):
  194 
  195         share = copy.deepcopy(self.share)
  196         share['status'] = constants.STATUS_AVAILABLE
  197         share['revert_to_snapshot_support'] = True
  198         share["instances"] = [
  199             {
  200                 "id": "fakeid",
  201                 "access_rules_status": constants.ACCESS_STATE_ACTIVE,
  202             },
  203         ]
  204         share = fake_share.fake_share(**share)
  205         snapshot = copy.deepcopy(self.snapshot)
  206         snapshot['status'] = constants.STATUS_AVAILABLE
  207         body = {'revert': {'snapshot_id': '2'}}
  208         req = fakes.HTTPRequest.blank(
  209             '/shares/1/action', use_admin_context=False, version='2.27')
  210         mock_validate_revert_parameters = self.mock_object(
  211             self.controller, '_validate_revert_parameters',
  212             mock.Mock(return_value=body['revert']))
  213         mock_get = self.mock_object(
  214             share_api.API, 'get', mock.Mock(return_value=share))
  215         mock_get_snapshot = self.mock_object(
  216             share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
  217         mock_get_latest_snapshot_for_share = self.mock_object(
  218             share_api.API, 'get_latest_snapshot_for_share',
  219             mock.Mock(return_value=snapshot))
  220         mock_revert_to_snapshot = self.mock_object(
  221             share_api.API, 'revert_to_snapshot')
  222 
  223         response = self.controller._revert(req, '1', body=body)
  224 
  225         self.assertEqual(202, response.status_int)
  226         mock_validate_revert_parameters.assert_called_once_with(
  227             utils.IsAMatcher(context.RequestContext), body)
  228         mock_get.assert_called_once_with(
  229             utils.IsAMatcher(context.RequestContext), '1')
  230         mock_get_snapshot.assert_called_once_with(
  231             utils.IsAMatcher(context.RequestContext), '2')
  232         mock_get_latest_snapshot_for_share.assert_called_once_with(
  233             utils.IsAMatcher(context.RequestContext), '1')
  234         mock_revert_to_snapshot.assert_called_once_with(
  235             utils.IsAMatcher(context.RequestContext), share, snapshot)
  236 
  237     def test__revert_not_supported(self):
  238 
  239         share = copy.deepcopy(self.share)
  240         share['revert_to_snapshot_support'] = False
  241         share = fake_share.fake_share(**share)
  242         snapshot = copy.deepcopy(self.snapshot)
  243         snapshot['status'] = constants.STATUS_AVAILABLE
  244         snapshot['share_id'] = 'wrong_id'
  245         body = {'revert': {'snapshot_id': '2'}}
  246         req = fakes.HTTPRequest.blank(
  247             '/shares/1/action', use_admin_context=False, version='2.27')
  248         self.mock_object(
  249             self.controller, '_validate_revert_parameters',
  250             mock.Mock(return_value=body['revert']))
  251         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
  252         self.mock_object(
  253             share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
  254 
  255         self.assertRaises(webob.exc.HTTPBadRequest,
  256                           self.controller._revert,
  257                           req,
  258                           '1',
  259                           body=body)
  260 
  261     def test__revert_id_mismatch(self):
  262 
  263         share = copy.deepcopy(self.share)
  264         share['status'] = constants.STATUS_AVAILABLE
  265         share['revert_to_snapshot_support'] = True
  266         share = fake_share.fake_share(**share)
  267         snapshot = copy.deepcopy(self.snapshot)
  268         snapshot['status'] = constants.STATUS_AVAILABLE
  269         snapshot['share_id'] = 'wrong_id'
  270         body = {'revert': {'snapshot_id': '2'}}
  271         req = fakes.HTTPRequest.blank(
  272             '/shares/1/action', use_admin_context=False, version='2.27')
  273         self.mock_object(
  274             self.controller, '_validate_revert_parameters',
  275             mock.Mock(return_value=body['revert']))
  276         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
  277         self.mock_object(
  278             share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
  279 
  280         self.assertRaises(webob.exc.HTTPBadRequest,
  281                           self.controller._revert,
  282                           req,
  283                           '1',
  284                           body=body)
  285 
  286     @ddt.data(
  287         {
  288             'share_status': constants.STATUS_ERROR,
  289             'share_is_busy': False,
  290             'snapshot_status': constants.STATUS_AVAILABLE,
  291         }, {
  292             'share_status': constants.STATUS_AVAILABLE,
  293             'share_is_busy': True,
  294             'snapshot_status': constants.STATUS_AVAILABLE,
  295         }, {
  296             'share_status': constants.STATUS_AVAILABLE,
  297             'share_is_busy': False,
  298             'snapshot_status': constants.STATUS_ERROR,
  299         })
  300     @ddt.unpack
  301     def test__revert_invalid_status(self, share_status, share_is_busy,
  302                                     snapshot_status):
  303 
  304         share = copy.deepcopy(self.share)
  305         share['status'] = share_status
  306         share['is_busy'] = share_is_busy
  307         share['revert_to_snapshot_support'] = True
  308         share = fake_share.fake_share(**share)
  309         snapshot = copy.deepcopy(self.snapshot)
  310         snapshot['status'] = snapshot_status
  311         body = {'revert': {'snapshot_id': '2'}}
  312         req = fakes.HTTPRequest.blank(
  313             '/shares/1/action', use_admin_context=False, version='2.27')
  314         self.mock_object(
  315             self.controller, '_validate_revert_parameters',
  316             mock.Mock(return_value=body['revert']))
  317         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
  318         self.mock_object(
  319             share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
  320 
  321         self.assertRaises(webob.exc.HTTPConflict,
  322                           self.controller._revert,
  323                           req,
  324                           '1',
  325                           body=body)
  326 
  327     def test__revert_snapshot_latest_not_found(self):
  328 
  329         share = copy.deepcopy(self.share)
  330         share['status'] = constants.STATUS_AVAILABLE
  331         share['revert_to_snapshot_support'] = True
  332         share = fake_share.fake_share(**share)
  333         snapshot = copy.deepcopy(self.snapshot)
  334         snapshot['status'] = constants.STATUS_AVAILABLE
  335         body = {'revert': {'snapshot_id': '2'}}
  336         req = fakes.HTTPRequest.blank(
  337             '/shares/1/action', use_admin_context=False, version='2.27')
  338         self.mock_object(
  339             self.controller, '_validate_revert_parameters',
  340             mock.Mock(return_value=body['revert']))
  341         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
  342         self.mock_object(
  343             share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
  344         self.mock_object(
  345             share_api.API, 'get_latest_snapshot_for_share',
  346             mock.Mock(return_value=None))
  347 
  348         self.assertRaises(webob.exc.HTTPBadRequest,
  349                           self.controller._revert,
  350                           req,
  351                           '1',
  352                           body=body)
  353 
  354     def test__revert_snapshot_access_applying(self):
  355 
  356         share = copy.deepcopy(self.share)
  357         share['status'] = constants.STATUS_AVAILABLE
  358         share['revert_to_snapshot_support'] = True
  359         share["instances"] = [
  360             {
  361                 "id": "fakeid",
  362                 "access_rules_status": constants.SHARE_INSTANCE_RULES_SYNCING,
  363             },
  364         ]
  365         share = fake_share.fake_share(**share)
  366         snapshot = copy.deepcopy(self.snapshot)
  367         snapshot['status'] = constants.STATUS_AVAILABLE
  368         body = {'revert': {'snapshot_id': '2'}}
  369         req = fakes.HTTPRequest.blank(
  370             '/shares/1/action', use_admin_context=False, version='2.27')
  371         self.mock_object(
  372             self.controller, '_validate_revert_parameters',
  373             mock.Mock(return_value=body['revert']))
  374         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
  375         self.mock_object(share_api.API, 'get_snapshot',
  376                          mock.Mock(return_value=snapshot))
  377         self.mock_object(share_api.API, 'get_latest_snapshot_for_share',
  378                          mock.Mock(return_value=snapshot))
  379         self.mock_object(share_api.API, 'revert_to_snapshot')
  380 
  381         self.assertRaises(webob.exc.HTTPConflict,
  382                           self.controller._revert,
  383                           req,
  384                           '1',
  385                           body=body)
  386 
  387     def test__revert_snapshot_not_latest(self):
  388 
  389         share = copy.deepcopy(self.share)
  390         share['status'] = constants.STATUS_AVAILABLE
  391         share['revert_to_snapshot_support'] = True
  392         share = fake_share.fake_share(**share)
  393         snapshot = copy.deepcopy(self.snapshot)
  394         snapshot['status'] = constants.STATUS_AVAILABLE
  395         latest_snapshot = copy.deepcopy(self.snapshot)
  396         latest_snapshot['status'] = constants.STATUS_AVAILABLE
  397         latest_snapshot['id'] = '3'
  398         body = {'revert': {'snapshot_id': '2'}}
  399         req = fakes.HTTPRequest.blank(
  400             '/shares/1/action', use_admin_context=False, version='2.27')
  401         self.mock_object(
  402             self.controller, '_validate_revert_parameters',
  403             mock.Mock(return_value=body['revert']))
  404         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
  405         self.mock_object(
  406             share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
  407         self.mock_object(
  408             share_api.API, 'get_latest_snapshot_for_share',
  409             mock.Mock(return_value=latest_snapshot))
  410 
  411         self.assertRaises(webob.exc.HTTPConflict,
  412                           self.controller._revert,
  413                           req,
  414                           '1',
  415                           body=body)
  416 
  417     @ddt.data(
  418         {
  419             'caught': exception.ShareNotFound,
  420             'exc_args': {
  421                 'share_id': '1',
  422             },
  423             'thrown': webob.exc.HTTPNotFound,
  424         }, {
  425             'caught': exception.ShareSnapshotNotFound,
  426             'exc_args': {
  427                 'snapshot_id': '2',
  428             },
  429             'thrown': webob.exc.HTTPBadRequest,
  430         }, {
  431             'caught': exception.ShareSizeExceedsAvailableQuota,
  432             'exc_args': {},
  433             'thrown': webob.exc.HTTPForbidden,
  434         }, {
  435             'caught': exception.ReplicationException,
  436             'exc_args': {
  437                 'reason': 'catastrophic failure',
  438             },
  439             'thrown': webob.exc.HTTPBadRequest,
  440         })
  441     @ddt.unpack
  442     def test__revert_exception(self, caught, exc_args, thrown):
  443 
  444         body = {'revert': {'snapshot_id': '2'}}
  445         req = fakes.HTTPRequest.blank(
  446             '/shares/1/action', use_admin_context=False, version='2.27')
  447         self.mock_object(
  448             self.controller, '_validate_revert_parameters',
  449             mock.Mock(return_value=body['revert']))
  450         self.mock_object(
  451             share_api.API, 'get', mock.Mock(side_effect=caught(**exc_args)))
  452 
  453         self.assertRaises(thrown,
  454                           self.controller._revert,
  455                           req,
  456                           '1',
  457                           body=body)
  458 
  459     def test_validate_revert_parameters(self):
  460 
  461         body = {'revert': {'snapshot_id': 'fake_snapshot_id'}}
  462 
  463         result = self.controller._validate_revert_parameters(
  464             'fake_context', body)
  465 
  466         self.assertEqual(body['revert'], result)
  467 
  468     @ddt.data(
  469         None,
  470         {},
  471         {'manage': {'snapshot_id': 'fake_snapshot_id'}},
  472         {'revert': {'share_id': 'fake_snapshot_id'}},
  473         {'revert': {'snapshot_id': ''}},
  474     )
  475     def test_validate_revert_parameters_invalid(self, body):
  476 
  477         self.assertRaises(webob.exc.HTTPBadRequest,
  478                           self.controller._validate_revert_parameters,
  479                           'fake_context',
  480                           body)
  481 
  482     @ddt.data("2.0", "2.1")
  483     def test_share_create_original(self, microversion):
  484         self.mock_object(share_api.API, 'create', self.create_mock)
  485         body = {"share": copy.deepcopy(self.share)}
  486         req = fakes.HTTPRequest.blank('/shares', version=microversion)
  487 
  488         res_dict = self.controller.create(req, body)
  489 
  490         expected = self._get_expected_share_detailed_response(
  491             self.share, version=microversion)
  492         self.assertEqual(expected, res_dict)
  493 
  494     @ddt.data("2.2", "2.3")
  495     def test_share_create_with_snapshot_support_without_cg(self, microversion):
  496         self.mock_object(share_api.API, 'create', self.create_mock)
  497         body = {"share": copy.deepcopy(self.share)}
  498         req = fakes.HTTPRequest.blank('/shares', version=microversion)
  499 
  500         res_dict = self.controller.create(req, body)
  501 
  502         expected = self._get_expected_share_detailed_response(
  503             self.share, version=microversion)
  504         self.assertEqual(expected, res_dict)
  505 
  506     def test_share_create_with_share_group(self):
  507         self.mock_object(share_api.API, 'create', self.create_mock)
  508         body = {"share": copy.deepcopy(self.share)}
  509         req = fakes.HTTPRequest.blank('/shares', version="2.31",
  510                                       experimental=True)
  511 
  512         res_dict = self.controller.create(req, body)
  513 
  514         expected = self._get_expected_share_detailed_response(
  515             self.share, version="2.31")
  516         self.assertEqual(expected, res_dict)
  517 
  518     def test_share_create_with_sg_and_availability_zone(self):
  519         sg_id = 'fake_sg_id'
  520         az_id = 'bar_az_id'
  521         self.mock_object(share_api.API, 'create', self.create_mock)
  522         self.mock_object(
  523             db, 'availability_zone_get',
  524             mock.Mock(return_value=type('ReqAZ', (object, ), {"id": az_id})))
  525         self.mock_object(
  526             db, 'share_group_get',
  527             mock.Mock(return_value={"availability_zone_id": az_id}))
  528         body = {"share": {
  529             "size": 100,
  530             "share_proto": "fakeproto",
  531             "availability_zone": az_id,
  532             "share_group_id": sg_id,
  533         }}
  534         req = fakes.HTTPRequest.blank(
  535             '/shares', version="2.31", experimental=True)
  536 
  537         self.controller.create(req, body)
  538 
  539         db.availability_zone_get.assert_called_once_with(
  540             req.environ['manila.context'], az_id)
  541         db.share_group_get.assert_called_once_with(
  542             req.environ['manila.context'], sg_id)
  543         share_api.API.create.assert_called_once_with(
  544             req.environ['manila.context'],
  545             body['share']['share_proto'].upper(),
  546             body['share']['size'],
  547             None,
  548             None,
  549             share_group_id=body['share']['share_group_id'],
  550             is_public=False,
  551             metadata=None,
  552             snapshot_id=None,
  553             availability_zone=az_id)
  554 
  555     def test_share_create_with_sg_and_different_availability_zone(self):
  556         sg_id = 'fake_sg_id'
  557         sg_az = 'foo_az_id'
  558         req_az = 'bar_az_id'
  559         self.mock_object(share_api.API, 'create', self.create_mock)
  560         self.mock_object(
  561             db, 'availability_zone_get',
  562             mock.Mock(return_value=type('ReqAZ', (object, ), {"id": req_az})))
  563         self.mock_object(
  564             db, 'share_group_get',
  565             mock.Mock(return_value={"availability_zone_id": sg_az}))
  566         body = {"share": {
  567             "size": 100,
  568             "share_proto": "fakeproto",
  569             "availability_zone": req_az,
  570             "share_group_id": sg_id,
  571         }}
  572         req = fakes.HTTPRequest.blank(
  573             '/shares', version="2.31", experimental=True)
  574 
  575         self.assertRaises(
  576             exception.InvalidInput, self.controller.create, req, body)
  577 
  578         db.availability_zone_get.assert_called_once_with(
  579             req.environ['manila.context'], req_az)
  580         db.share_group_get.assert_called_once_with(
  581             req.environ['manila.context'], sg_id)
  582         self.assertEqual(0, share_api.API.create.call_count)
  583 
  584     def test_share_create_with_nonexistent_share_group(self):
  585         sg_id = 'fake_sg_id'
  586         self.mock_object(share_api.API, 'create', self.create_mock)
  587         self.mock_object(db, 'availability_zone_get')
  588         self.mock_object(
  589             db, 'share_group_get',
  590             mock.Mock(side_effect=exception.ShareGroupNotFound(
  591                 share_group_id=sg_id)))
  592         body = {"share": {
  593             "size": 100,
  594             "share_proto": "fakeproto",
  595             "share_group_id": sg_id,
  596         }}
  597         req = fakes.HTTPRequest.blank(
  598             '/shares', version="2.31", experimental=True)
  599 
  600         self.assertRaises(
  601             webob.exc.HTTPNotFound, self.controller.create, req, body)
  602 
  603         self.assertEqual(0, db.availability_zone_get.call_count)
  604         self.assertEqual(0, share_api.API.create.call_count)
  605         db.share_group_get.assert_called_once_with(
  606             req.environ['manila.context'], sg_id)
  607 
  608     def test_share_create_with_valid_default_share_type(self):
  609         self.mock_object(share_types, 'get_share_type_by_name',
  610                          mock.Mock(return_value=self.vt))
  611         CONF.set_default("default_share_type", self.vt['name'])
  612         self.mock_object(share_api.API, 'create', self.create_mock)
  613 
  614         body = {"share": copy.deepcopy(self.share)}
  615         req = fakes.HTTPRequest.blank('/shares', version='2.7')
  616         res_dict = self.controller.create(req, body)
  617 
  618         expected = self._get_expected_share_detailed_response(self.share,
  619                                                               version='2.7')
  620         share_types.get_share_type_by_name.assert_called_once_with(
  621             utils.IsAMatcher(context.RequestContext), self.vt['name'])
  622         self.assertEqual(expected, res_dict)
  623 
  624     def test_share_create_with_invalid_default_share_type(self):
  625         self.mock_object(
  626             share_types, 'get_default_share_type',
  627             mock.Mock(side_effect=exception.ShareTypeNotFoundByName(
  628                 self.vt['name'])),
  629         )
  630         CONF.set_default("default_share_type", self.vt['name'])
  631         req = fakes.HTTPRequest.blank('/shares', version='2.7')
  632         self.assertRaises(exception.ShareTypeNotFoundByName,
  633                           self.controller.create, req, {'share': self.share})
  634         share_types.get_default_share_type.assert_called_once_with()
  635 
  636     def test_share_create_with_replication(self):
  637         self.mock_object(share_api.API, 'create', self.create_mock)
  638 
  639         body = {"share": copy.deepcopy(self.share)}
  640         req = fakes.HTTPRequest.blank(
  641             '/shares', version=share_replicas.MIN_SUPPORTED_API_VERSION)
  642 
  643         res_dict = self.controller.create(req, body)
  644 
  645         expected = self._get_expected_share_detailed_response(
  646             self.share, version=share_replicas.MIN_SUPPORTED_API_VERSION)
  647 
  648         self.assertEqual(expected, res_dict)
  649 
  650     def test_share_create_with_share_net(self):
  651         shr = {
  652             "size": 100,
  653             "name": "Share Test Name",
  654             "description": "Share Test Desc",
  655             "share_proto": "fakeproto",
  656             "availability_zone": "zone1:host1",
  657             "share_network_id": "fakenetid"
  658         }
  659         create_mock = mock.Mock(return_value=stubs.stub_share('1',
  660                                 display_name=shr['name'],
  661                                 display_description=shr['description'],
  662                                 size=shr['size'],
  663                                 share_proto=shr['share_proto'].upper(),
  664                                 availability_zone=shr['availability_zone'],
  665                                 share_network_id=shr['share_network_id']))
  666         self.mock_object(share_api.API, 'create', create_mock)
  667         self.mock_object(share_api.API, 'get_share_network', mock.Mock(
  668             return_value={'id': 'fakenetid'}))
  669         self.mock_object(
  670             db, 'share_network_subnet_get_by_availability_zone_id')
  671 
  672         body = {"share": copy.deepcopy(shr)}
  673         req = fakes.HTTPRequest.blank('/shares', version='2.7')
  674         res_dict = self.controller.create(req, body)
  675 
  676         expected = self._get_expected_share_detailed_response(
  677             shr, version='2.7')
  678         self.assertDictMatch(expected, res_dict)
  679         # pylint: disable=unsubscriptable-object
  680         self.assertEqual("fakenetid",
  681                          create_mock.call_args[1]['share_network_id'])
  682 
  683     @ddt.data("2.15", "2.16")
  684     def test_share_create_original_with_user_id(self, microversion):
  685         self.mock_object(share_api.API, 'create', self.create_mock)
  686         body = {"share": copy.deepcopy(self.share)}
  687         req = fakes.HTTPRequest.blank('/shares', version=microversion)
  688 
  689         res_dict = self.controller.create(req, body)
  690 
  691         expected = self._get_expected_share_detailed_response(
  692             self.share, version=microversion)
  693 
  694         self.assertEqual(expected, res_dict)
  695 
  696     @ddt.data(test_utils.annotated('v2.0_az_unsupported', ('2.0', False)),
  697               test_utils.annotated('v2.0_az_supported', ('2.0', True)),
  698               test_utils.annotated('v2.47_az_unsupported', ('2.47', False)),
  699               test_utils.annotated('v2.47_az_supported', ('2.47', True)))
  700     @ddt.unpack
  701     def test_share_create_with_share_type_azs(self, version, az_supported):
  702         """For API version<2.48, AZ validation should not be performed."""
  703         self.mock_object(share_api.API, 'create', self.create_mock)
  704         create_args = copy.deepcopy(self.share)
  705         create_args['availability_zone'] = 'az1' if az_supported else 'az2'
  706         create_args['share_type'] = uuidutils.generate_uuid()
  707         stype_with_azs = copy.deepcopy(self.vt)
  708         stype_with_azs['extra_specs']['availability_zones'] = 'az1,az3'
  709         self.mock_object(share_types, 'get_share_type', mock.Mock(
  710             return_value=stype_with_azs))
  711 
  712         req = fakes.HTTPRequest.blank('/shares', version=version)
  713 
  714         res_dict = self.controller.create(req, {'share': create_args})
  715 
  716         expected = self._get_expected_share_detailed_response(
  717             values=self.share, version=version)
  718 
  719         self.assertEqual(expected, res_dict)
  720 
  721     @ddt.data(*set([
  722         test_utils.annotated('v2.48_share_from_snap', ('2.48', True)),
  723         test_utils.annotated('v2.48_share_not_from_snap', ('2.48', False)),
  724         test_utils.annotated('v%s_share_from_snap' % LATEST_MICROVERSION,
  725                              (LATEST_MICROVERSION, True)),
  726         test_utils.annotated('v%s_share_not_from_snap' % LATEST_MICROVERSION,
  727                              (LATEST_MICROVERSION, False))]))
  728     @ddt.unpack
  729     def test_share_create_az_not_in_share_type(self, version, snap):
  730         """For API version>=2.48, AZ validation should be performed."""
  731         self.mock_object(share_api.API, 'create', self.create_mock)
  732         create_args = copy.deepcopy(self.share)
  733         create_args['availability_zone'] = 'az2'
  734         create_args['share_type'] = (uuidutils.generate_uuid() if not snap
  735                                      else None)
  736         create_args['snapshot_id'] = (uuidutils.generate_uuid() if snap
  737                                       else None)
  738         stype_with_azs = copy.deepcopy(self.vt)
  739         stype_with_azs['extra_specs']['availability_zones'] = 'az1 , az3'
  740         self.mock_object(share_types, 'get_share_type', mock.Mock(
  741             return_value=stype_with_azs))
  742         self.mock_object(share_api.API, 'get_snapshot',
  743                          stubs.stub_snapshot_get)
  744 
  745         req = fakes.HTTPRequest.blank('/shares', version=version)
  746 
  747         self.assertRaises(webob.exc.HTTPBadRequest,
  748                           self.controller.create,
  749                           req, {'share': create_args})
  750         share_api.API.create.assert_not_called()
  751 
  752     def test_migration_start(self):
  753         share = db_utils.create_share()
  754         share_network = db_utils.create_share_network()
  755         share_type = {'share_type_id': 'fake_type_id'}
  756         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
  757                                       use_admin_context=True, version='2.29')
  758         req.method = 'POST'
  759         req.headers['content-type'] = 'application/json'
  760         req.api_version_request.experimental = True
  761         context = req.environ['manila.context']
  762 
  763         self.mock_object(db, 'share_network_get', mock.Mock(
  764             return_value=share_network))
  765         self.mock_object(db, 'share_type_get', mock.Mock(
  766             return_value=share_type))
  767 
  768         body = {
  769             'migration_start': {
  770                 'host': 'fake_host',
  771                 'preserve_metadata': True,
  772                 'preserve_snapshots': True,
  773                 'writable': True,
  774                 'nondisruptive': True,
  775                 'new_share_network_id': 'fake_net_id',
  776                 'new_share_type_id': 'fake_type_id',
  777             }
  778         }
  779         method = 'migration_start'
  780 
  781         self.mock_object(share_api.API, 'migration_start',
  782                          mock.Mock(return_value=202))
  783         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
  784 
  785         response = getattr(self.controller, method)(req, share['id'], body)
  786 
  787         self.assertEqual(202, response.status_int)
  788 
  789         share_api.API.get.assert_called_once_with(context, share['id'])
  790         share_api.API.migration_start.assert_called_once_with(
  791             context, share, 'fake_host', False, True, True, True, True,
  792             new_share_network=share_network, new_share_type=share_type)
  793         db.share_network_get.assert_called_once_with(
  794             context, 'fake_net_id')
  795         db.share_type_get.assert_called_once_with(
  796             context, 'fake_type_id')
  797 
  798     def test_migration_start_conflict(self):
  799         share = db_utils.create_share()
  800         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
  801                                       use_admin_context=True)
  802         req.method = 'POST'
  803         req.headers['content-type'] = 'application/json'
  804         req.api_version_request = api_version.APIVersionRequest('2.29')
  805         req.api_version_request.experimental = True
  806 
  807         body = {
  808             'migration_start': {
  809                 'host': 'fake_host',
  810                 'preserve_metadata': True,
  811                 'preserve_snapshots': True,
  812                 'writable': True,
  813                 'nondisruptive': True,
  814             }
  815         }
  816 
  817         self.mock_object(share_api.API, 'migration_start',
  818                          mock.Mock(side_effect=exception.Conflict(err='err')))
  819 
  820         self.assertRaises(webob.exc.HTTPConflict,
  821                           self.controller.migration_start,
  822                           req, share['id'], body)
  823 
  824     @ddt.data('nondisruptive', 'writable', 'preserve_metadata',
  825               'preserve_snapshots', 'host', 'body')
  826     def test_migration_start_missing_mandatory(self, param):
  827         share = db_utils.create_share()
  828         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
  829                                       use_admin_context=True,
  830                                       version='2.29')
  831         req.method = 'POST'
  832         req.headers['content-type'] = 'application/json'
  833         req.api_version_request.experimental = True
  834 
  835         body = {
  836             'migration_start': {
  837                 'host': 'fake_host',
  838                 'preserve_metadata': True,
  839                 'preserve_snapshots': True,
  840                 'writable': True,
  841                 'nondisruptive': True,
  842             }
  843         }
  844 
  845         if param == 'body':
  846             body.pop('migration_start')
  847         else:
  848             body['migration_start'].pop(param)
  849 
  850         method = 'migration_start'
  851 
  852         self.mock_object(share_api.API, 'migration_start')
  853         self.mock_object(share_api.API, 'get',
  854                          mock.Mock(return_value=share))
  855 
  856         self.assertRaises(webob.exc.HTTPBadRequest,
  857                           getattr(self.controller, method),
  858                           req, 'fake_id', body)
  859 
  860     @ddt.data('nondisruptive', 'writable', 'preserve_metadata',
  861               'preserve_snapshots', 'force_host_assisted_migration')
  862     def test_migration_start_non_boolean(self, param):
  863         share = db_utils.create_share()
  864         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
  865                                       use_admin_context=True,
  866                                       version='2.29')
  867         req.method = 'POST'
  868         req.headers['content-type'] = 'application/json'
  869         req.api_version_request.experimental = True
  870 
  871         body = {
  872             'migration_start': {
  873                 'host': 'fake_host',
  874                 'preserve_metadata': True,
  875                 'preserve_snapshots': True,
  876                 'writable': True,
  877                 'nondisruptive': True,
  878             }
  879         }
  880 
  881         body['migration_start'][param] = None
  882 
  883         method = 'migration_start'
  884 
  885         self.mock_object(share_api.API, 'migration_start')
  886         self.mock_object(share_api.API, 'get',
  887                          mock.Mock(return_value=share))
  888 
  889         self.assertRaises(webob.exc.HTTPBadRequest,
  890                           getattr(self.controller, method),
  891                           req, 'fake_id', body)
  892 
  893     def test_migration_start_no_share_id(self):
  894         req = fakes.HTTPRequest.blank('/shares/%s/action' % 'fake_id',
  895                                       use_admin_context=True, version='2.29')
  896         req.method = 'POST'
  897         req.headers['content-type'] = 'application/json'
  898         req.api_version_request.experimental = True
  899 
  900         body = {'migration_start': {'host': 'fake_host'}}
  901         method = 'migration_start'
  902 
  903         self.mock_object(share_api.API, 'get',
  904                          mock.Mock(side_effect=[exception.NotFound]))
  905         self.assertRaises(webob.exc.HTTPNotFound,
  906                           getattr(self.controller, method),
  907                           req, 'fake_id', body)
  908 
  909     def test_migration_start_new_share_network_not_found(self):
  910         share = db_utils.create_share()
  911         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
  912                                       use_admin_context=True, version='2.29')
  913         context = req.environ['manila.context']
  914         req.method = 'POST'
  915         req.headers['content-type'] = 'application/json'
  916         req.api_version_request.experimental = True
  917 
  918         body = {
  919             'migration_start': {
  920                 'host': 'fake_host',
  921                 'preserve_metadata': True,
  922                 'preserve_snapshots': True,
  923                 'writable': True,
  924                 'nondisruptive': True,
  925                 'new_share_network_id': 'nonexistent'}}
  926 
  927         self.mock_object(db, 'share_network_get',
  928                          mock.Mock(side_effect=exception.NotFound()))
  929         self.assertRaises(webob.exc.HTTPBadRequest,
  930                           self.controller.migration_start,
  931                           req, share['id'], body)
  932         db.share_network_get.assert_called_once_with(context, 'nonexistent')
  933 
  934     def test_migration_start_new_share_type_not_found(self):
  935         share = db_utils.create_share()
  936         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
  937                                       use_admin_context=True, version='2.29')
  938         context = req.environ['manila.context']
  939         req.method = 'POST'
  940         req.headers['content-type'] = 'application/json'
  941         req.api_version_request.experimental = True
  942 
  943         body = {
  944             'migration_start': {
  945                 'host': 'fake_host',
  946                 'preserve_metadata': True,
  947                 'preserve_snapshots': True,
  948                 'writable': True,
  949                 'nondisruptive': True,
  950                 'new_share_type_id': 'nonexistent'}}
  951 
  952         self.mock_object(db, 'share_type_get',
  953                          mock.Mock(side_effect=exception.NotFound()))
  954         self.assertRaises(webob.exc.HTTPBadRequest,
  955                           self.controller.migration_start,
  956                           req, share['id'], body)
  957         db.share_type_get.assert_called_once_with(context, 'nonexistent')
  958 
  959     def test_migration_start_invalid_force_host_assisted_migration(self):
  960         share = db_utils.create_share()
  961         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
  962                                       use_admin_context=True, version='2.29')
  963         req.method = 'POST'
  964         req.headers['content-type'] = 'application/json'
  965         req.api_version_request.experimental = True
  966 
  967         body = {'migration_start': {'host': 'fake_host',
  968                                     'force_host_assisted_migration': 'fake'}}
  969         method = 'migration_start'
  970 
  971         self.assertRaises(webob.exc.HTTPBadRequest,
  972                           getattr(self.controller, method),
  973                           req, share['id'], body)
  974 
  975     @ddt.data('writable', 'preserve_metadata')
  976     def test_migration_start_invalid_writable_preserve_metadata(
  977             self, parameter):
  978         share = db_utils.create_share()
  979         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
  980                                       use_admin_context=True, version='2.29')
  981         req.method = 'POST'
  982         req.headers['content-type'] = 'application/json'
  983         req.api_version_request.experimental = True
  984 
  985         body = {'migration_start': {'host': 'fake_host',
  986                                     parameter: 'invalid'}}
  987 
  988         self.assertRaises(webob.exc.HTTPBadRequest,
  989                           self.controller.migration_start, req, share['id'],
  990                           body)
  991 
  992     @ddt.data(constants.TASK_STATE_MIGRATION_ERROR, None)
  993     def test_reset_task_state(self, task_state):
  994         share = db_utils.create_share()
  995         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
  996                                       use_admin_context=True, version='2.22')
  997         req.method = 'POST'
  998         req.headers['content-type'] = 'application/json'
  999         req.api_version_request.experimental = True
 1000 
 1001         update = {'task_state': task_state}
 1002         body = {'reset_task_state': update}
 1003 
 1004         self.mock_object(db, 'share_update')
 1005 
 1006         response = self.controller.reset_task_state(req, share['id'], body)
 1007 
 1008         self.assertEqual(202, response.status_int)
 1009 
 1010         db.share_update.assert_called_once_with(utils.IsAMatcher(
 1011             context.RequestContext), share['id'], update)
 1012 
 1013     def test_reset_task_state_error_body(self):
 1014         share = db_utils.create_share()
 1015         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
 1016                                       use_admin_context=True, version='2.22')
 1017         req.method = 'POST'
 1018         req.headers['content-type'] = 'application/json'
 1019         req.api_version_request.experimental = True
 1020 
 1021         update = {'error': 'error'}
 1022         body = {'reset_task_state': update}
 1023 
 1024         self.assertRaises(webob.exc.HTTPBadRequest,
 1025                           self.controller.reset_task_state, req, share['id'],
 1026                           body)
 1027 
 1028     def test_reset_task_state_error_invalid(self):
 1029         share = db_utils.create_share()
 1030         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
 1031                                       use_admin_context=True, version='2.22')
 1032         req.method = 'POST'
 1033         req.headers['content-type'] = 'application/json'
 1034         req.api_version_request.experimental = True
 1035 
 1036         update = {'task_state': 'error'}
 1037         body = {'reset_task_state': update}
 1038 
 1039         self.assertRaises(webob.exc.HTTPBadRequest,
 1040                           self.controller.reset_task_state, req, share['id'],
 1041                           body)
 1042 
 1043     def test_reset_task_state_not_found(self):
 1044         share = db_utils.create_share()
 1045         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
 1046                                       use_admin_context=True, version='2.22')
 1047         req.method = 'POST'
 1048         req.headers['content-type'] = 'application/json'
 1049         req.api_version_request.experimental = True
 1050 
 1051         update = {'task_state': constants.TASK_STATE_MIGRATION_ERROR}
 1052         body = {'reset_task_state': update}
 1053 
 1054         self.mock_object(db, 'share_update',
 1055                          mock.Mock(side_effect=exception.NotFound()))
 1056 
 1057         self.assertRaises(webob.exc.HTTPNotFound,
 1058                           self.controller.reset_task_state, req, share['id'],
 1059                           body)
 1060 
 1061         db.share_update.assert_called_once_with(utils.IsAMatcher(
 1062             context.RequestContext), share['id'], update)
 1063 
 1064     def test_migration_complete(self):
 1065         share = db_utils.create_share()
 1066         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
 1067                                       use_admin_context=True, version='2.22')
 1068         req.method = 'POST'
 1069         req.headers['content-type'] = 'application/json'
 1070         req.api_version_request.experimental = True
 1071 
 1072         body = {'migration_complete': None}
 1073 
 1074         self.mock_object(share_api.API, 'get',
 1075                          mock.Mock(return_value=share))
 1076 
 1077         self.mock_object(share_api.API, 'migration_complete')
 1078 
 1079         response = self.controller.migration_complete(req, share['id'], body)
 1080 
 1081         self.assertEqual(202, response.status_int)
 1082 
 1083         share_api.API.migration_complete.assert_called_once_with(
 1084             utils.IsAMatcher(context.RequestContext), share)
 1085 
 1086     def test_migration_complete_not_found(self):
 1087         share = db_utils.create_share()
 1088         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
 1089                                       use_admin_context=True, version='2.22')
 1090         req.method = 'POST'
 1091         req.headers['content-type'] = 'application/json'
 1092         req.api_version_request.experimental = True
 1093 
 1094         body = {'migration_complete': None}
 1095 
 1096         self.mock_object(share_api.API, 'get',
 1097                          mock.Mock(side_effect=exception.NotFound()))
 1098         self.mock_object(share_api.API, 'migration_complete')
 1099 
 1100         self.assertRaises(webob.exc.HTTPNotFound,
 1101                           self.controller.migration_complete, req, share['id'],
 1102                           body)
 1103 
 1104     def test_migration_cancel(self):
 1105         share = db_utils.create_share()
 1106         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
 1107                                       use_admin_context=True, version='2.22')
 1108         req.method = 'POST'
 1109         req.headers['content-type'] = 'application/json'
 1110         req.api_version_request.experimental = True
 1111 
 1112         body = {'migration_cancel': None}
 1113 
 1114         self.mock_object(share_api.API, 'get',
 1115                          mock.Mock(return_value=share))
 1116 
 1117         self.mock_object(share_api.API, 'migration_cancel')
 1118 
 1119         response = self.controller.migration_cancel(req, share['id'], body)
 1120 
 1121         self.assertEqual(202, response.status_int)
 1122 
 1123         share_api.API.migration_cancel.assert_called_once_with(
 1124             utils.IsAMatcher(context.RequestContext), share)
 1125 
 1126     def test_migration_cancel_not_found(self):
 1127         share = db_utils.create_share()
 1128         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
 1129                                       use_admin_context=True, version='2.22')
 1130         req.method = 'POST'
 1131         req.headers['content-type'] = 'application/json'
 1132         req.api_version_request.experimental = True
 1133 
 1134         body = {'migration_cancel': None}
 1135 
 1136         self.mock_object(share_api.API, 'get',
 1137                          mock.Mock(side_effect=exception.NotFound()))
 1138         self.mock_object(share_api.API, 'migration_cancel')
 1139 
 1140         self.assertRaises(webob.exc.HTTPNotFound,
 1141                           self.controller.migration_cancel, req, share['id'],
 1142                           body)
 1143 
 1144     def test_migration_get_progress(self):
 1145         share = db_utils.create_share(
 1146             task_state=constants.TASK_STATE_MIGRATION_SUCCESS)
 1147         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
 1148                                       use_admin_context=True, version='2.22')
 1149         req.method = 'POST'
 1150         req.headers['content-type'] = 'application/json'
 1151         req.api_version_request.experimental = True
 1152 
 1153         body = {'migration_get_progress': None}
 1154         expected = {
 1155             'total_progress': 'fake',
 1156             'task_state': constants.TASK_STATE_MIGRATION_SUCCESS,
 1157         }
 1158 
 1159         self.mock_object(share_api.API, 'get',
 1160                          mock.Mock(return_value=share))
 1161 
 1162         self.mock_object(share_api.API, 'migration_get_progress',
 1163                          mock.Mock(return_value=expected))
 1164 
 1165         response = self.controller.migration_get_progress(req, share['id'],
 1166                                                           body)
 1167 
 1168         self.assertEqual(expected, response)
 1169 
 1170         share_api.API.migration_get_progress.assert_called_once_with(
 1171             utils.IsAMatcher(context.RequestContext), share)
 1172 
 1173     def test_migration_get_progress_not_found(self):
 1174         share = db_utils.create_share()
 1175         req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
 1176                                       use_admin_context=True, version='2.22')
 1177         req.method = 'POST'
 1178         req.headers['content-type'] = 'application/json'
 1179         req.api_version_request.experimental = True
 1180 
 1181         body = {'migration_get_progress': None}
 1182 
 1183         self.mock_object(share_api.API, 'get',
 1184                          mock.Mock(side_effect=exception.NotFound()))
 1185         self.mock_object(share_api.API, 'migration_get_progress')
 1186 
 1187         self.assertRaises(webob.exc.HTTPNotFound,
 1188                           self.controller.migration_get_progress, req,
 1189                           share['id'], body)
 1190 
 1191     def test_share_create_from_snapshot_without_share_net_no_parent(self):
 1192         shr = {
 1193             "size": 100,
 1194             "name": "Share Test Name",
 1195             "description": "Share Test Desc",
 1196             "share_proto": "fakeproto",
 1197             "availability_zone": "zone1:host1",
 1198             "snapshot_id": 333,
 1199             "share_network_id": None,
 1200         }
 1201         create_mock = mock.Mock(return_value=stubs.stub_share('1',
 1202                                 display_name=shr['name'],
 1203                                 display_description=shr['description'],
 1204                                 size=shr['size'],
 1205                                 share_proto=shr['share_proto'].upper(),
 1206                                 snapshot_id=shr['snapshot_id'],
 1207                                 instance=dict(
 1208                                     availability_zone=shr['availability_zone'],
 1209                                     share_network_id=shr['share_network_id'])))
 1210         self.mock_object(share_api.API, 'create', create_mock)
 1211         body = {"share": copy.deepcopy(shr)}
 1212         req = fakes.HTTPRequest.blank('/shares', version='2.7')
 1213 
 1214         res_dict = self.controller.create(req, body)
 1215 
 1216         expected = self._get_expected_share_detailed_response(
 1217             shr, version='2.7')
 1218         self.assertEqual(expected, res_dict)
 1219 
 1220     def test_share_create_from_snapshot_without_share_net_parent_exists(self):
 1221         shr = {
 1222             "size": 100,
 1223             "name": "Share Test Name",
 1224             "description": "Share Test Desc",
 1225             "share_proto": "fakeproto",
 1226             "availability_zone": "zone1:host1",
 1227             "snapshot_id": 333,
 1228             "share_network_id": None,
 1229         }
 1230         parent_share_net = 444
 1231         create_mock = mock.Mock(return_value=stubs.stub_share('1',
 1232                                 display_name=shr['name'],
 1233                                 display_description=shr['description'],
 1234                                 size=shr['size'],
 1235                                 share_proto=shr['share_proto'].upper(),
 1236                                 snapshot_id=shr['snapshot_id'],
 1237                                 instance=dict(
 1238                                     availability_zone=shr['availability_zone'],
 1239                                     share_network_id=shr['share_network_id'])))
 1240         self.mock_object(share_api.API, 'create', create_mock)
 1241         self.mock_object(share_api.API, 'get_snapshot',
 1242                          stubs.stub_snapshot_get)
 1243         parent_share = stubs.stub_share(
 1244             '1', instance={'share_network_id': parent_share_net},
 1245             create_share_from_snapshot_support=True)
 1246         self.mock_object(share_api.API, 'get', mock.Mock(
 1247             return_value=parent_share))
 1248         self.mock_object(share_api.API, 'get_share_network', mock.Mock(
 1249             return_value={'id': parent_share_net}))
 1250         self.mock_object(
 1251             db, 'share_network_subnet_get_by_availability_zone_id')
 1252 
 1253         body = {"share": copy.deepcopy(shr)}
 1254         req = fakes.HTTPRequest.blank('/shares', version='2.7')
 1255 
 1256         res_dict = self.controller.create(req, body)
 1257 
 1258         expected = self._get_expected_share_detailed_response(
 1259             shr, version='2.7')
 1260         self.assertEqual(expected, res_dict)
 1261         # pylint: disable=unsubscriptable-object
 1262         self.assertEqual(parent_share_net,
 1263                          create_mock.call_args[1]['share_network_id'])
 1264 
 1265     def test_share_create_from_snapshot_with_share_net_equals_parent(self):
 1266         parent_share_net = 444
 1267         shr = {
 1268             "size": 100,
 1269             "name": "Share Test Name",
 1270             "description": "Share Test Desc",
 1271             "share_proto": "fakeproto",
 1272             "availability_zone": "zone1:host1",
 1273             "snapshot_id": 333,
 1274             "share_network_id": parent_share_net,
 1275         }
 1276         create_mock = mock.Mock(return_value=stubs.stub_share('1',
 1277                                 display_name=shr['name'],
 1278                                 display_description=shr['description'],
 1279                                 size=shr['size'],
 1280                                 share_proto=shr['share_proto'].upper(),
 1281                                 snapshot_id=shr['snapshot_id'],
 1282                                 instance=dict(
 1283                                     availability_zone=shr['availability_zone'],
 1284                                     share_network_id=shr['share_network_id'])))
 1285         self.mock_object(share_api.API, 'create', create_mock)
 1286         self.mock_object(share_api.API, 'get_snapshot',
 1287                          stubs.stub_snapshot_get)
 1288         parent_share = stubs.stub_share(
 1289             '1', instance={'share_network_id': parent_share_net},
 1290             create_share_from_snapshot_support=True)
 1291         self.mock_object(share_api.API, 'get', mock.Mock(
 1292             return_value=parent_share))
 1293         self.mock_object(share_api.API, 'get_share_network', mock.Mock(
 1294             return_value={'id': parent_share_net}))
 1295         self.mock_object(
 1296             db, 'share_network_subnet_get_by_availability_zone_id')
 1297 
 1298         body = {"share": copy.deepcopy(shr)}
 1299         req = fakes.HTTPRequest.blank('/shares', version='2.7')
 1300         res_dict = self.controller.create(req, body)
 1301         expected = self._get_expected_share_detailed_response(
 1302             shr, version='2.7')
 1303         self.assertDictMatch(expected, res_dict)
 1304         # pylint: disable=unsubscriptable-object
 1305         self.assertEqual(parent_share_net,
 1306                          create_mock.call_args[1]['share_network_id'])
 1307 
 1308     def test_share_create_from_snapshot_invalid_share_net(self):
 1309         self.mock_object(share_api.API, 'create')
 1310         shr = {
 1311             "size": 100,
 1312             "name": "Share Test Name",
 1313             "description": "Share Test Desc",
 1314             "share_proto": "fakeproto",
 1315             "availability_zone": "zone1:host1",
 1316             "snapshot_id": 333,
 1317             "share_network_id": 1234,
 1318         }
 1319         body = {"share": shr}
 1320         req = fakes.HTTPRequest.blank('/shares', version='2.7')
 1321         self.assertRaises(webob.exc.HTTPBadRequest,
 1322                           self.controller.create, req, body)
 1323 
 1324     def test_share_create_from_snapshot_not_supported(self):
 1325         parent_share_net = 444
 1326         self.mock_object(share_api.API, 'create')
 1327         shr = {
 1328             "size": 100,
 1329             "name": "Share Test Name",
 1330             "description": "Share Test Desc",
 1331             "share_proto": "fakeproto",
 1332             "availability_zone": "zone1:host1",
 1333             "snapshot_id": 333,
 1334             "share_network_id": parent_share_net,
 1335         }
 1336         parent_share = stubs.stub_share(
 1337             '1', instance={'share_network_id': parent_share_net},
 1338             create_share_from_snapshot_support=False)
 1339         self.mock_object(share_api.API, 'get', mock.Mock(
 1340             return_value=parent_share))
 1341         self.mock_object(share_api.API, 'get_share_network', mock.Mock(
 1342             return_value={'id': parent_share_net}))
 1343 
 1344         body = {"share": shr}
 1345         req = fakes.HTTPRequest.blank('/shares', version='2.24')
 1346         self.assertRaises(webob.exc.HTTPBadRequest,
 1347                           self.controller.create, req, body)
 1348 
 1349     def test_share_creation_fails_with_bad_size(self):
 1350         shr = {"size": '',
 1351                "name": "Share Test Name",
 1352                "description": "Share Test Desc",
 1353                "share_proto": "fakeproto",
 1354                "availability_zone": "zone1:host1"}
 1355         body = {"share": shr}
 1356         req = fakes.HTTPRequest.blank('/shares', version='2.7')
 1357         self.assertRaises(exception.InvalidInput,
 1358                           self.controller.create, req, body)
 1359 
 1360     def test_share_create_no_body(self):
 1361         req = fakes.HTTPRequest.blank('/shares', version='2.7')
 1362         self.assertRaises(webob.exc.HTTPUnprocessableEntity,
 1363                           self.controller.create, req, {})
 1364 
 1365     def test_share_create_invalid_availability_zone(self):
 1366         self.mock_object(
 1367             db,
 1368             'availability_zone_get',
 1369             mock.Mock(side_effect=exception.AvailabilityZoneNotFound(id='id'))
 1370         )
 1371         body = {"share": copy.deepcopy(self.share)}
 1372 
 1373         req = fakes.HTTPRequest.blank('/shares', version='2.7')
 1374         self.assertRaises(webob.exc.HTTPNotFound,
 1375                           self.controller.create,
 1376                           req,
 1377                           body)
 1378 
 1379     def test_share_show(self):
 1380         req = fakes.HTTPRequest.blank('/shares/1')
 1381         expected = self._get_expected_share_detailed_response()
 1382 
 1383         res_dict = self.controller.show(req, '1')
 1384 
 1385         self.assertEqual(expected, res_dict)
 1386 
 1387     def test_share_show_with_share_group(self):
 1388         req = fakes.HTTPRequest.blank(
 1389             '/shares/1', version='2.31', experimental=True)
 1390         expected = self._get_expected_share_detailed_response(version='2.31')
 1391 
 1392         res_dict = self.controller.show(req, '1')
 1393 
 1394         self.assertDictMatch(expected, res_dict)
 1395 
 1396     def test_share_show_with_share_group_earlier_version(self):
 1397         req = fakes.HTTPRequest.blank(
 1398             '/shares/1', version='2.23', experimental=True)
 1399         expected = self._get_expected_share_detailed_response(version='2.23')
 1400 
 1401         res_dict = self.controller.show(req, '1')
 1402 
 1403         self.assertDictMatch(expected, res_dict)
 1404 
 1405     def test_share_show_with_share_type_name(self):
 1406         req = fakes.HTTPRequest.blank('/shares/1', version='2.6')
 1407 
 1408         res_dict = self.controller.show(req, '1')
 1409 
 1410         expected = self._get_expected_share_detailed_response(version='2.6')
 1411         self.assertEqual(expected, res_dict)
 1412 
 1413     @ddt.data("2.15", "2.16")
 1414     def test_share_show_with_user_id(self, microversion):
 1415         req = fakes.HTTPRequest.blank('/shares/1', version=microversion)
 1416 
 1417         res_dict = self.controller.show(req, '1')
 1418 
 1419         expected = self._get_expected_share_detailed_response(
 1420             version=microversion)
 1421 
 1422         self.assertEqual(expected, res_dict)
 1423 
 1424     def test_share_show_admin(self):
 1425         req = fakes.HTTPRequest.blank('/shares/1', use_admin_context=True)
 1426         expected = self._get_expected_share_detailed_response(admin=True)
 1427 
 1428         res_dict = self.controller.show(req, '1')
 1429 
 1430         self.assertEqual(expected, res_dict)
 1431 
 1432     def test_share_show_no_share(self):
 1433         self.mock_object(share_api.API, 'get',
 1434                          stubs.stub_share_get_notfound)
 1435         req = fakes.HTTPRequest.blank('/shares/1')
 1436         self.assertRaises(webob.exc.HTTPNotFound,
 1437                           self.controller.show,
 1438                           req, '1')
 1439 
 1440     def test_share_show_with_replication_type(self):
 1441         req = fakes.HTTPRequest.blank(
 1442             '/shares/1', version=share_replicas.MIN_SUPPORTED_API_VERSION)
 1443         res_dict = self.controller.show(req, '1')
 1444 
 1445         expected = self._get_expected_share_detailed_response(
 1446             version=share_replicas.MIN_SUPPORTED_API_VERSION)
 1447 
 1448         self.assertEqual(expected, res_dict)
 1449 
 1450     @ddt.data(('2.10', True), ('2.27', True), ('2.28', False))
 1451     @ddt.unpack
 1452     def test_share_show_access_rules_status_translated(self, version,
 1453                                                        translated):
 1454         share = db_utils.create_share(
 1455             access_rules_status=constants.SHARE_INSTANCE_RULES_SYNCING,
 1456             status=constants.STATUS_AVAILABLE)
 1457         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
 1458         req = fakes.HTTPRequest.blank(
 1459             '/shares/%s' % share['id'], version=version)
 1460 
 1461         res_dict = self.controller.show(req, share['id'])
 1462 
 1463         expected = (constants.STATUS_OUT_OF_SYNC if translated else
 1464                     constants.SHARE_INSTANCE_RULES_SYNCING)
 1465 
 1466         self.assertEqual(expected, res_dict['share']['access_rules_status'])
 1467 
 1468     def test_share_delete(self):
 1469         req = fakes.HTTPRequest.blank('/shares/1')
 1470         resp = self.controller.delete(req, 1)
 1471         self.assertEqual(202, resp.status_int)
 1472 
 1473     def test_share_delete_has_replicas(self):
 1474         req = fakes.HTTPRequest.blank('/shares/1')
 1475         self.mock_object(share_api.API, 'get',
 1476                          mock.Mock(return_value=self.share))
 1477         self.mock_object(share_api.API, 'delete',
 1478                          mock.Mock(side_effect=exception.Conflict(err='err')))
 1479 
 1480         self.assertRaises(
 1481             webob.exc.HTTPConflict, self.controller.delete, req, 1)
 1482 
 1483     def test_share_delete_in_share_group_param_not_provided(self):
 1484         fake_share = stubs.stub_share('fake_share',
 1485                                       share_group_id='fake_group_id')
 1486         self.mock_object(share_api.API, 'get',
 1487                          mock.Mock(return_value=fake_share))
 1488         req = fakes.HTTPRequest.blank('/shares/1')
 1489         self.assertRaises(webob.exc.HTTPBadRequest,
 1490                           self.controller.delete, req, 1)
 1491 
 1492     def test_share_delete_in_share_group(self):
 1493         fake_share = stubs.stub_share('fake_share',
 1494                                       share_group_id='fake_group_id')
 1495         self.mock_object(share_api.API, 'get',
 1496                          mock.Mock(return_value=fake_share))
 1497         req = fakes.HTTPRequest.blank(
 1498             '/shares/1?share_group_id=fake_group_id')
 1499         resp = self.controller.delete(req, 1)
 1500         self.assertEqual(202, resp.status_int)
 1501 
 1502     def test_share_delete_in_share_group_wrong_id(self):
 1503         fake_share = stubs.stub_share('fake_share',
 1504                                       share_group_id='fake_group_id')
 1505         self.mock_object(share_api.API, 'get',
 1506                          mock.Mock(return_value=fake_share))
 1507         req = fakes.HTTPRequest.blank(
 1508             '/shares/1?share_group_id=not_fake_group_id')
 1509         self.assertRaises(webob.exc.HTTPBadRequest,
 1510                           self.controller.delete, req, 1)
 1511 
 1512     def test_share_update(self):
 1513         shr = self.share
 1514         body = {"share": shr}
 1515 
 1516         req = fakes.HTTPRequest.blank('/share/1')
 1517         res_dict = self.controller.update(req, 1, body)
 1518         self.assertEqual(shr["display_name"], res_dict['share']["name"])
 1519         self.assertEqual(shr["display_description"],
 1520                          res_dict['share']["description"])
 1521         self.assertEqual(shr['is_public'],
 1522                          res_dict['share']['is_public'])
 1523 
 1524     def test_share_update_with_share_group(self):
 1525         shr = self.share
 1526         body = {"share": shr}
 1527 
 1528         req = fakes.HTTPRequest.blank(
 1529             '/share/1', version="2.31", experimental=True)
 1530 
 1531         res_dict = self.controller.update(req, 1, body)
 1532 
 1533         self.assertIsNone(res_dict['share']["share_group_id"])
 1534         self.assertIsNone(
 1535             res_dict['share']["source_share_group_snapshot_member_id"])
 1536 
 1537     def test_share_not_updates_size(self):
 1538         req = fakes.HTTPRequest.blank('/share/1')
 1539         res_dict = self.controller.update(req, 1, {"share": self.share})
 1540         self.assertNotEqual(res_dict['share']["size"], self.share["size"])
 1541 
 1542     def test_share_delete_no_share(self):
 1543         self.mock_object(share_api.API, 'get',
 1544                          stubs.stub_share_get_notfound)
 1545         req = fakes.HTTPRequest.blank('/shares/1')
 1546         self.assertRaises(webob.exc.HTTPNotFound,
 1547                           self.controller.delete,
 1548                           req,
 1549                           1)
 1550 
 1551     @ddt.data({'use_admin_context': False, 'version': '2.4'},
 1552               {'use_admin_context': True, 'version': '2.4'},
 1553               {'use_admin_context': True, 'version': '2.35'},
 1554               {'use_admin_context': False, 'version': '2.35'},
 1555               {'use_admin_context': True, 'version': '2.36'},
 1556               {'use_admin_context': False, 'version': '2.36'},
 1557               {'use_admin_context': True, 'version': '2.42'},
 1558               {'use_admin_context': False, 'version': '2.42'})
 1559     @ddt.unpack
 1560     def test_share_list_summary_with_search_opts(self, use_admin_context,
 1561                                                  version):
 1562         search_opts = {
 1563             'name': 'fake_name',
 1564             'status': constants.STATUS_AVAILABLE,
 1565             'share_server_id': 'fake_share_server_id',
 1566             'share_type_id': 'fake_share_type_id',
 1567             'snapshot_id': 'fake_snapshot_id',
 1568             'share_network_id': 'fake_share_network_id',
 1569             'metadata': '%7B%27k1%27%3A+%27v1%27%7D',  # serialized k1=v1
 1570             'extra_specs': '%7B%27k2%27%3A+%27v2%27%7D',  # serialized k2=v2
 1571             'sort_key': 'fake_sort_key',
 1572             'sort_dir': 'fake_sort_dir',
 1573             'limit': '1',
 1574             'offset': '1',
 1575             'is_public': 'False',
 1576             'export_location_id': 'fake_export_location_id',
 1577             'export_location_path': 'fake_export_location_path',
 1578         }
 1579         if (api_version.APIVersionRequest(version) >=
 1580                 api_version.APIVersionRequest('2.36')):
 1581             search_opts.update(
 1582                 {'display_name~': 'fake',
 1583                  'display_description~': 'fake'})
 1584         if (api_version.APIVersionRequest(version) >=
 1585                 api_version.APIVersionRequest('2.42')):
 1586             search_opts.update({'with_count': 'true'})
 1587         if use_admin_context:
 1588             search_opts['host'] = 'fake_host'
 1589         # fake_key should be filtered for non-admin
 1590         url = '/shares?fake_key=fake_value'
 1591         for k, v in search_opts.items():
 1592             url = url + '&' + k + '=' + v
 1593         req = fakes.HTTPRequest.blank(url, version=version,
 1594                                       use_admin_context=use_admin_context)
 1595 
 1596         shares = [
 1597             {'id': 'id1', 'display_name': 'n1'},
 1598             {'id': 'id2', 'display_name': 'n2'},
 1599             {'id': 'id3', 'display_name': 'n3'},
 1600         ]
 1601         self.mock_object(share_api.API, 'get_all',
 1602                          mock.Mock(return_value=[shares[1]]))
 1603 
 1604         result = self.controller.index(req)
 1605 
 1606         search_opts_expected = {
 1607             'display_name': search_opts['name'],
 1608             'status': search_opts['status'],
 1609             'share_server_id': search_opts['share_server_id'],
 1610             'share_type_id': search_opts['share_type_id'],
 1611             'snapshot_id': search_opts['snapshot_id'],
 1612             'share_network_id': search_opts['share_network_id'],
 1613             'metadata': {'k1': 'v1'},
 1614             'extra_specs': {'k2': 'v2'},
 1615             'is_public': 'False',
 1616             'limit': '1',
 1617             'offset': '1'
 1618         }
 1619         if (api_version.APIVersionRequest(version) >=
 1620                 api_version.APIVersionRequest('2.35')):
 1621             search_opts_expected['export_location_id'] = (
 1622                 search_opts['export_location_id'])
 1623             search_opts_expected['export_location_path'] = (
 1624                 search_opts['export_location_path'])
 1625         if (api_version.APIVersionRequest(version) >=
 1626                 api_version.APIVersionRequest('2.36')):
 1627             search_opts_expected.update(
 1628                 {'display_name~': search_opts['display_name~'],
 1629                  'display_description~': search_opts['display_description~']})
 1630 
 1631         if use_admin_context:
 1632             search_opts_expected.update({'fake_key': 'fake_value'})
 1633             search_opts_expected['host'] = search_opts['host']
 1634         share_api.API.get_all.assert_called_once_with(
 1635             req.environ['manila.context'],
 1636             sort_key=search_opts['sort_key'],
 1637             sort_dir=search_opts['sort_dir'],
 1638             search_opts=search_opts_expected,
 1639         )
 1640         self.assertEqual(1, len(result['shares']))
 1641         self.assertEqual(shares[1]['id'], result['shares'][0]['id'])
 1642         self.assertEqual(
 1643             shares[1]['display_name'], result['shares'][0]['name'])
 1644         if (api_version.APIVersionRequest(version) >=
 1645                 api_version.APIVersionRequest('2.42')):
 1646             self.assertEqual(1, result['count'])
 1647 
 1648     @ddt.data({'use_admin_context': True, 'version': '2.42'},
 1649               {'use_admin_context': False, 'version': '2.42'})
 1650     @ddt.unpack
 1651     def test_share_list_summary_with_search_opt_count_0(self,
 1652                                                         use_admin_context,
 1653                                                         version):
 1654         search_opts = {
 1655             'sort_key': 'fake_sort_key',
 1656             'sort_dir': 'fake_sort_dir',
 1657             'with_count': 'true'
 1658         }
 1659         if use_admin_context:
 1660             search_opts['host'] = 'fake_host'
 1661         # fake_key should be filtered
 1662         url = '/shares?fake_key=fake_value'
 1663         for k, v in search_opts.items():
 1664             url = url + '&' + k + '=' + v
 1665         req = fakes.HTTPRequest.blank(url, version=version,
 1666                                       use_admin_context=use_admin_context)
 1667 
 1668         self.mock_object(share_api.API, 'get_all',
 1669                          mock.Mock(return_value=[]))
 1670 
 1671         result = self.controller.index(req)
 1672 
 1673         search_opts_expected = {}
 1674 
 1675         if use_admin_context:
 1676             search_opts_expected.update({'fake_key': 'fake_value'})
 1677             search_opts_expected['host'] = search_opts['host']
 1678         share_api.API.get_all.assert_called_once_with(
 1679             req.environ['manila.context'],
 1680             sort_key=search_opts['sort_key'],
 1681             sort_dir=search_opts['sort_dir'],
 1682             search_opts=search_opts_expected,
 1683         )
 1684         self.assertEqual(0, len(result['shares']))
 1685         self.assertEqual(0, result['count'])
 1686 
 1687     def test_share_list_summary(self):
 1688         self.mock_object(share_api.API, 'get_all',
 1689                          stubs.stub_share_get_all_by_project)
 1690         req = fakes.HTTPRequest.blank('/shares')
 1691         res_dict = self.controller.index(req)
 1692         expected = {
 1693             'shares': [
 1694                 {
 1695                     'name': 'displayname',
 1696                     'id': '1',
 1697                     'links': [
 1698                         {
 1699                             'href': 'http://localhost/v1/fake/shares/1',
 1700                             'rel': 'self'
 1701                         },
 1702                         {
 1703                             'href': 'http://localhost/fake/shares/1',
 1704                             'rel': 'bookmark'
 1705                         }
 1706                     ],
 1707                 }
 1708             ]
 1709         }
 1710         self.assertEqual(expected, res_dict)
 1711 
 1712     @ddt.data({'use_admin_context': False, 'version': '2.4'},
 1713               {'use_admin_context': True, 'version': '2.4'},
 1714               {'use_admin_context': True, 'version': '2.35'},
 1715               {'use_admin_context': False, 'version': '2.35'},
 1716               {'use_admin_context': True, 'version': '2.42'},
 1717               {'use_admin_context': False, 'version': '2.42'})
 1718     @ddt.unpack
 1719     def test_share_list_detail_with_search_opts(self, use_admin_context,
 1720                                                 version):
 1721         search_opts = {
 1722             'name': 'fake_name',
 1723             'status': constants.STATUS_AVAILABLE,
 1724             'share_server_id': 'fake_share_server_id',
 1725             'share_type_id': 'fake_share_type_id',
 1726             'snapshot_id': 'fake_snapshot_id',
 1727             'share_network_id': 'fake_share_network_id',
 1728             'metadata': '%7B%27k1%27%3A+%27v1%27%7D',  # serialized k1=v1
 1729             'extra_specs': '%7B%27k2%27%3A+%27v2%27%7D',  # serialized k2=v2
 1730             'sort_key': 'fake_sort_key',
 1731             'sort_dir': 'fake_sort_dir',
 1732             'limit': '1',
 1733             'offset': '1',
 1734             'is_public': 'False',
 1735             'export_location_id': 'fake_export_location_id',
 1736             'export_location_path': 'fake_export_location_path',
 1737         }
 1738         if (api_version.APIVersionRequest(version) >=
 1739                 api_version.APIVersionRequest('2.42')):
 1740             search_opts.update({'with_count': 'true'})
 1741         if use_admin_context:
 1742             search_opts['host'] = 'fake_host'
 1743         # fake_key should be filtered for non-admin
 1744         url = '/shares/detail?fake_key=fake_value'
 1745         for k, v in search_opts.items():
 1746             url = url + '&' + k + '=' + v
 1747         req = fakes.HTTPRequest.blank(url, version=version,
 1748                                       use_admin_context=use_admin_context)
 1749 
 1750         shares = [
 1751             {'id': 'id1', 'display_name': 'n1'},
 1752             {
 1753                 'id': 'id2',
 1754                 'display_name': 'n2',
 1755                 'status': constants.STATUS_AVAILABLE,
 1756                 'snapshot_id': 'fake_snapshot_id',
 1757                 'instance': {
 1758                     'host': 'fake_host',
 1759                     'share_network_id': 'fake_share_network_id',
 1760                     'share_type_id': 'fake_share_type_id',
 1761                 },
 1762                 'has_replicas': False,
 1763             },
 1764             {'id': 'id3', 'display_name': 'n3'},
 1765         ]
 1766 
 1767         self.mock_object(share_api.API, 'get_all',
 1768                          mock.Mock(return_value=[shares[1]]))
 1769 
 1770         result = self.controller.detail(req)
 1771 
 1772         search_opts_expected = {
 1773             'display_name': search_opts['name'],
 1774             'status': search_opts['status'],
 1775             'share_server_id': search_opts['share_server_id'],
 1776             'share_type_id': search_opts['share_type_id'],
 1777             'snapshot_id': search_opts['snapshot_id'],
 1778             'share_network_id': search_opts['share_network_id'],
 1779             'metadata': {'k1': 'v1'},
 1780             'extra_specs': {'k2': 'v2'},
 1781             'is_public': 'False',
 1782             'limit': '1',
 1783             'offset': '1'
 1784         }
 1785 
 1786         if (api_version.APIVersionRequest(version) >=
 1787                 api_version.APIVersionRequest('2.35')):
 1788             search_opts_expected['export_location_id'] = (
 1789                 search_opts['export_location_id'])
 1790             search_opts_expected['export_location_path'] = (
 1791                 search_opts['export_location_path'])
 1792 
 1793         if use_admin_context:
 1794             search_opts_expected.update({'fake_key': 'fake_value'})
 1795             search_opts_expected['host'] = search_opts['host']
 1796         share_api.API.get_all.assert_called_once_with(
 1797             req.environ['manila.context'],
 1798             sort_key=search_opts['sort_key'],
 1799             sort_dir=search_opts['sort_dir'],
 1800             search_opts=search_opts_expected,
 1801         )
 1802         self.assertEqual(1, len(result['shares']))
 1803         self.assertEqual(shares[1]['id'], result['shares'][0]['id'])
 1804         self.assertEqual(
 1805             shares[1]['display_name'], result['shares'][0]['name'])
 1806         self.assertEqual(
 1807             shares[1]['snapshot_id'], result['shares'][0]['snapshot_id'])
 1808         self.assertEqual(
 1809             shares[1]['status'], result['shares'][0]['status'])
 1810         self.assertEqual(
 1811             shares[1]['instance']['share_type_id'],
 1812             result['shares'][0]['share_type'])
 1813         self.assertEqual(
 1814             shares[1]['snapshot_id'], result['shares'][0]['snapshot_id'])
 1815         if use_admin_context:
 1816             self.assertEqual(
 1817                 shares[1]['instance']['host'], result['shares'][0]['host'])
 1818         self.assertEqual(
 1819             shares[1]['instance']['share_network_id'],
 1820             result['shares'][0]['share_network_id'])
 1821         if (api_version.APIVersionRequest(version) >=
 1822                 api_version.APIVersionRequest('2.42')):
 1823             self.assertEqual(1, result['count'])
 1824 
 1825     def _list_detail_common_expected(self, admin=False):
 1826         share_dict = {
 1827             'status': 'fakestatus',
 1828             'description': 'displaydesc',
 1829             'export_location': 'fake_location',
 1830             'export_locations': ['fake_location', 'fake_location2'],
 1831             'availability_zone': 'fakeaz',
 1832             'name': 'displayname',
 1833             'share_proto': 'FAKEPROTO',
 1834             'metadata': {},
 1835             'project_id': 'fakeproject',
 1836             'id': '1',
 1837             'snapshot_id': '2',
 1838             'snapshot_support': True,
 1839             'share_network_id': None,
 1840             'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
 1841             'size': 1,
 1842             'share_type': '1',
 1843             'volume_type': '1',
 1844             'is_public': False,
 1845             'links': [
 1846                 {
 1847                     'href': 'http://localhost/v1/fake/shares/1',
 1848                     'rel': 'self'
 1849                 },
 1850                 {
 1851                     'href': 'http://localhost/fake/shares/1',
 1852                     'rel': 'bookmark'
 1853                 }
 1854             ],
 1855         }
 1856         if admin:
 1857             share_dict['host'] = 'fakehost'
 1858         return {'shares': [share_dict]}
 1859 
 1860     def _list_detail_test_common(self, req, expected):
 1861         self.mock_object(share_api.API, 'get_all',
 1862                          stubs.stub_share_get_all_by_project)
 1863         res_dict = self.controller.detail(req)
 1864         self.assertDictListMatch(expected['shares'], res_dict['shares'])
 1865         self.assertEqual(res_dict['shares'][0]['volume_type'],
 1866                          res_dict['shares'][0]['share_type'])
 1867 
 1868     def test_share_list_detail(self):
 1869         env = {'QUERY_STRING': 'name=Share+Test+Name'}
 1870         req = fakes.HTTPRequest.blank('/shares/detail', environ=env)
 1871         expected = self._list_detail_common_expected()
 1872         expected['shares'][0].pop('snapshot_support')
 1873         self._list_detail_test_common(req, expected)
 1874 
 1875     def test_share_list_detail_with_share_group(self):
 1876         env = {'QUERY_STRING': 'name=Share+Test+Name'}
 1877         req = fakes.HTTPRequest.blank(
 1878             '/shares/detail', environ=env, version="2.31", experimental=True)
 1879         expected = self._list_detail_common_expected()
 1880         expected['shares'][0]['task_state'] = None
 1881         expected['shares'][0]['share_type_name'] = None
 1882         expected['shares'][0].pop('export_location')
 1883         expected['shares'][0].pop('export_locations')
 1884         expected['shares'][0]['access_rules_status'] = 'active'
 1885         expected['shares'][0]['replication_type'] = None
 1886         expected['shares'][0]['has_replicas'] = False
 1887         expected['shares'][0]['user_id'] = 'fakeuser'
 1888         expected['shares'][0]['create_share_from_snapshot_support'] = True
 1889         expected['shares'][0]['revert_to_snapshot_support'] = False
 1890         expected['shares'][0]['share_group_id'] = None
 1891         expected['shares'][0]['source_share_group_snapshot_member_id'] = None
 1892         self._list_detail_test_common(req, expected)
 1893 
 1894     def test_share_list_detail_with_task_state(self):
 1895         env = {'QUERY_STRING': 'name=Share+Test+Name'}
 1896         req = fakes.HTTPRequest.blank('/shares/detail', environ=env,
 1897                                       version="2.5")
 1898         expected = self._list_detail_common_expected()
 1899         expected['shares'][0]['task_state'] = None
 1900         self._list_detail_test_common(req, expected)
 1901 
 1902     def test_share_list_detail_without_export_locations(self):
 1903         env = {'QUERY_STRING': 'name=Share+Test+Name'}
 1904         req = fakes.HTTPRequest.blank('/shares/detail', environ=env,
 1905                                       version="2.9")
 1906         expected = self._list_detail_common_expected()
 1907         expected['shares'][0]['task_state'] = None
 1908         expected['shares'][0]['share_type_name'] = None
 1909         expected['shares'][0].pop('export_location')
 1910         expected['shares'][0].pop('export_locations')
 1911         self._list_detail_test_common(req, expected)
 1912 
 1913     def test_share_list_detail_with_replication_type(self):
 1914         self.mock_object(share_api.API, 'get_all',
 1915                          stubs.stub_share_get_all_by_project)
 1916         env = {'QUERY_STRING': 'name=Share+Test+Name'}
 1917         req = fakes.HTTPRequest.blank(
 1918             '/shares/detail', environ=env,
 1919             version=share_replicas.MIN_SUPPORTED_API_VERSION)
 1920         res_dict = self.controller.detail(req)
 1921         expected = {
 1922             'shares': [
 1923                 {
 1924                     'status': 'fakestatus',
 1925                     'description': 'displaydesc',
 1926                     'availability_zone': 'fakeaz',
 1927                     'name': 'displayname',
 1928                     'share_proto': 'FAKEPROTO',
 1929                     'metadata': {},
 1930                     'project_id': 'fakeproject',
 1931                     'access_rules_status': 'active',
 1932                     'id': '1',
 1933                     'snapshot_id': '2',
 1934                     'share_network_id': None,
 1935                     'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
 1936                     'size': 1,
 1937                     'share_type_name': None,
 1938                     'share_type': '1',
 1939                     'volume_type': '1',
 1940                     'is_public': False,
 1941                     'snapshot_support': True,
 1942                     'has_replicas': False,
 1943                     'replication_type': None,
 1944                     'task_state': None,
 1945                     'links': [
 1946                         {
 1947                             'href': 'http://localhost/v1/fake/shares/1',
 1948                             'rel': 'self'
 1949                         },
 1950                         {
 1951                             'href': 'http://localhost/fake/shares/1',
 1952                             'rel': 'bookmark'
 1953                         }
 1954                     ],
 1955                 }
 1956             ]
 1957         }
 1958         self.assertEqual(expected, res_dict)
 1959         self.assertEqual(res_dict['shares'][0]['volume_type'],
 1960                          res_dict['shares'][0]['share_type'])
 1961 
 1962     def test_remove_invalid_options(self):
 1963         ctx = context.RequestContext('fakeuser', 'fakeproject', is_admin=False)
 1964         search_opts = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'}
 1965         expected_opts = {'a': 'a', 'c': 'c'}
 1966         allowed_opts = ['a', 'c']
 1967         common.remove_invalid_options(ctx, search_opts, allowed_opts)
 1968         self.assertEqual(expected_opts, search_opts)
 1969 
 1970     def test_remove_invalid_options_admin(self):
 1971         ctx = context.RequestContext('fakeuser', 'fakeproject', is_admin=True)
 1972         search_opts = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'}
 1973         expected_opts = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'}
 1974         allowed_opts = ['a', 'c']
 1975         common.remove_invalid_options(ctx, search_opts, allowed_opts)
 1976         self.assertEqual(expected_opts, search_opts)
 1977 
 1978 
 1979 def _fake_access_get(self, ctxt, access_id):
 1980 
 1981     class Access(object):
 1982         def __init__(self, **kwargs):
 1983             self.STATE_NEW = 'fake_new'
 1984             self.STATE_ACTIVE = 'fake_active'
 1985             self.STATE_ERROR = 'fake_error'
 1986             self.params = kwargs
 1987             self.params['state'] = self.STATE_NEW
 1988             self.share_id = kwargs.get('share_id')
 1989             self.id = access_id
 1990 
 1991         def __getitem__(self, item):
 1992             return self.params[item]
 1993 
 1994     access = Access(access_id=access_id, share_id='fake_share_id')
 1995     return access
 1996 
 1997 
 1998 @ddt.ddt
 1999 class ShareActionsTest(test.TestCase):
 2000 
 2001     def setUp(self):
 2002         super(ShareActionsTest, self).setUp()
 2003         self.controller = shares.ShareController()
 2004         self.mock_object(share_api.API, 'get', stubs.stub_share_get)
 2005 
 2006     @ddt.unpack
 2007     @ddt.data(
 2008         {"access": {'access_type': 'ip', 'access_to': '127.0.0.1'},
 2009          "version": "2.7"},
 2010         {"access": {'access_type': 'user', 'access_to': '1' * 4},
 2011          "version": "2.7"},
 2012         {"access": {'access_type': 'user', 'access_to': '1' * 255},
 2013          "version": "2.7"},
 2014         {"access": {'access_type': 'user', 'access_to': 'fake{.-_\'`}'},
 2015          "version": "2.7"},
 2016         {"access": {'access_type': 'user',
 2017                     'access_to': 'MYDOMAIN-Administrator'},
 2018          "version": "2.7"},
 2019         {"access": {'access_type': 'user',
 2020                     'access_to': 'test group name'},
 2021          "version": "2.7"},
 2022         {"access": {'access_type': 'user',
 2023                     'access_to': 'group$.-_\'`{}'},
 2024          "version": "2.7"},
 2025         {"access": {'access_type': 'cert', 'access_to': 'x'},
 2026          "version": "2.7"},
 2027         {"access": {'access_type': 'cert', 'access_to': 'tenant.example.com'},
 2028          "version": "2.7"},
 2029         {"access": {'access_type': 'cert', 'access_to': 'x' * 64},
 2030          "version": "2.7"},
 2031         {"access": {'access_type': 'ip', 'access_to': 'ad80::abaa:0:c2:2'},
 2032          "version": "2.38"},
 2033         {"access": {'access_type': 'ip', 'access_to': 'AD80:ABAA::'},
 2034          "version": "2.38"},
 2035         {"access": {'access_type': 'ip', 'access_to': 'AD80::/36'},
 2036          "version": "2.38"},
 2037         {"access": {'access_type': 'ip', 'access_to': 'AD80:ABAA::/128'},
 2038          "version": "2.38"},
 2039         {"access": {'access_type': 'ip', 'access_to': '127.0.0.1'},
 2040          "version": "2.38"},
 2041         {"access": {'access_type': 'ip', 'access_to': '127.0.0.1',
 2042                     'metadata': {'test_key': 'test_value'}},
 2043          "version": "2.45"},
 2044         {"access": {'access_type': 'ip', 'access_to': '127.0.0.1',
 2045                     'metadata': {'k' * 255: 'v' * 1023}},
 2046          "version": "2.45"},
 2047     )
 2048     def test_allow_access(self, access, version):
 2049         self.mock_object(share_api.API,
 2050                          'allow_access',
 2051                          mock.Mock(return_value={'fake': 'fake'}))
 2052         self.mock_object(self.controller._access_view_builder, 'view',
 2053                          mock.Mock(return_value={'access':
 2054                                                  {'fake': 'fake'}}))
 2055         id = 'fake_share_id'
 2056         body = {'allow_access': access}
 2057         expected = {'access': {'fake': 'fake'}}
 2058         req = fakes.HTTPRequest.blank(
 2059             '/v2/tenant1/shares/%s/action' % id, version=version)
 2060 
 2061         res = self.controller.allow_access(req, id, body)
 2062 
 2063         self.assertEqual(expected, res)
 2064 
 2065     @ddt.unpack
 2066     @ddt.data(
 2067         {"access": {'access_type': 'error_type',
 2068                     'access_to': '127.0.0.1'},
 2069          "version": "2.7"},
 2070         {"access": {'access_type': 'ip', 'access_to': 'localhost'},
 2071          "version": "2.7"},
 2072         {"access": {'access_type': 'ip', 'access_to': '127.0.0.*'},
 2073          "version": "2.7"},
 2074         {"access": {'access_type': 'ip', 'access_to': '127.0.0.0/33'},
 2075          "version": "2.7"},
 2076         {"access": {'access_type': 'ip', 'access_to': '127.0.0.256'},
 2077          "version": "2.7"},
 2078         {"access": {'access_type': 'user', 'access_to': '1'},
 2079          "version": "2.7"},
 2080         {"access": {'access_type': 'user', 'access_to': '1' * 3},
 2081          "version": "2.7"},
 2082         {"access": {'access_type': 'user', 'access_to': '1' * 256},
 2083          "version": "2.7"},
 2084         {"access": {'access_type': 'user', 'access_to': 'root<>'},
 2085          "version": "2.7"},
 2086         {"access": {'access_type': 'user', 'access_to': 'group\\'},
 2087          "version": "2.7"},
 2088         {"access": {'access_type': 'user', 'access_to': '+=*?group'},
 2089          "version": "2.7"},
 2090         {"access": {'access_type': 'cert', 'access_to': ''},
 2091          "version": "2.7"},
 2092         {"access": {'access_type': 'cert', 'access_to': ' '},
 2093          "version": "2.7"},
 2094         {"access": {'access_type': 'cert', 'access_to': 'x' * 65},
 2095          "version": "2.7"},
 2096         {"access": {'access_type': 'ip', 'access_to': 'ad80::abaa:0:c2:2'},
 2097          "version": "2.37"},
 2098         {"access": {'access_type': 'ip', 'access_to': '127.4.0.3/33'},
 2099          "version": "2.38"},
 2100         {"access": {'access_type': 'ip', 'access_to': 'AD80:ABAA::*'},
 2101          "version": "2.38"},
 2102         {"access": {'access_type': 'ip', 'access_to': 'AD80::/129'},
 2103          "version": "2.38"},
 2104         {"access": {'access_type': 'ip', 'access_to': 'ad80::abaa:0:c2:2/64'},
 2105          "version": "2.38"},
 2106         {"access": {'access_type': 'ip', 'access_to': '127.0.0.1',
 2107                     'metadata': {'k' * 256: 'v' * 1024}},
 2108          "version": "2.45"},
 2109         {"access": {'access_type': 'ip', 'access_to': '127.0.0.1',
 2110                     'metadata': {'key': None}},
 2111          "version": "2.45"},
 2112     )
 2113     def test_allow_access_error(self, access, version):
 2114         id = 'fake_share_id'
 2115         body = {'allow_access': access}
 2116         req = fakes.HTTPRequest.blank('/v2/tenant1/shares/%s/action' % id,
 2117                                       version=version)
 2118         self.assertRaises(webob.exc.HTTPBadRequest,
 2119                           self.controller.allow_access, req, id, body)
 2120 
 2121     @ddt.unpack
 2122     @ddt.data(
 2123         {'exc': None, 'access_to': 'alice', 'version': '2.13'},
 2124         {'exc': webob.exc.HTTPBadRequest, 'access_to': 'alice',
 2125          'version': '2.11'}
 2126     )
 2127     def test_allow_access_ceph(self, exc, access_to, version):
 2128         share_id = "fake_id"
 2129         self.mock_object(share_api.API,
 2130                          'allow_access',
 2131                          mock.Mock(return_value={'fake': 'fake'}))
 2132         self.mock_object(self.controller._access_view_builder, 'view',
 2133                          mock.Mock(return_value={'access':
 2134                                                  {'fake': 'fake'}}))
 2135 
 2136         req = fakes.HTTPRequest.blank(
 2137             '/v2/shares/%s/action' % share_id, version=version)
 2138 
 2139         body = {'allow_access':
 2140                 {
 2141                     'access_type': 'cephx',
 2142                     'access_to': access_to,
 2143                     'access_level': 'rw'
 2144                 }}
 2145 
 2146         if exc:
 2147             self.assertRaises(exc, self.controller.allow_access, req, share_id,
 2148                               body)
 2149         else:
 2150             expected = {'access': {'fake': 'fake'}}
 2151             res = self.controller.allow_access(req, id, body)
 2152             self.assertEqual(expected, res)
 2153 
 2154     @ddt.data('2.1', '2.27')
 2155     def test_allow_access_access_rules_status_is_in_error(self, version):
 2156         share = db_utils.create_share(
 2157             access_rules_status=constants.SHARE_INSTANCE_RULES_ERROR)
 2158 
 2159         req = fakes.HTTPRequest.blank(
 2160             '/v2/shares/%s/action' % share['id'], version=version)
 2161         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
 2162         self.mock_object(share_api.API, 'allow_access')
 2163         if (api_version.APIVersionRequest(version) >=
 2164                 api_version.APIVersionRequest('2.7')):
 2165             key = 'allow_access'
 2166             method = self.controller.allow_access
 2167         else:
 2168             key = 'os-allow_access'
 2169             method = self.controller.allow_access_legacy
 2170 
 2171         body = {
 2172             key: {
 2173                 'access_type': 'user',
 2174                 'access_to': 'crimsontide',
 2175                 'access_level': 'rw',
 2176             }
 2177         }
 2178 
 2179         self.assertRaises(webob.exc.HTTPBadRequest,
 2180                           method, req, share['id'], body)
 2181         self.assertFalse(share_api.API.allow_access.called)
 2182 
 2183     @ddt.data(*itertools.product(
 2184         ('2.1', '2.27'), (constants.SHARE_INSTANCE_RULES_SYNCING,
 2185                           constants.STATUS_ACTIVE)))
 2186     @ddt.unpack
 2187     def test_allow_access_no_transitional_states(self, version, status):
 2188         share = db_utils.create_share(access_rules_status=status,
 2189                                       status=constants.STATUS_AVAILABLE)
 2190         req = fakes.HTTPRequest.blank(
 2191             '/v2/shares/%s/action' % share['id'], version=version)
 2192         ctxt = req.environ['manila.context']
 2193         access = {
 2194             'access_type': 'user',
 2195             'access_to': 'clemsontigers',
 2196             'access_level': 'rw',
 2197         }
 2198         expected_mapping = {
 2199             constants.SHARE_INSTANCE_RULES_SYNCING: constants.STATUS_NEW,
 2200             constants.SHARE_INSTANCE_RULES_ERROR:
 2201                 constants.ACCESS_STATE_ERROR,
 2202             constants.STATUS_ACTIVE: constants.ACCESS_STATE_ACTIVE,
 2203         }
 2204         share = db.share_get(ctxt, share['id'])
 2205         updated_access = db_utils.create_access(share_id=share['id'], **access)
 2206         expected_access = access
 2207         expected_access.update(
 2208             {
 2209                 'id': updated_access['id'],
 2210                 'state': expected_mapping[share['access_rules_status']],
 2211                 'share_id': updated_access['share_id'],
 2212             })
 2213 
 2214         if (api_version.APIVersionRequest(version) >=
 2215                 api_version.APIVersionRequest('2.7')):
 2216             key = 'allow_access'
 2217             method = self.controller.allow_access
 2218         else:
 2219             key = 'os-allow_access'
 2220             method = self.controller.allow_access_legacy
 2221         if (api_version.APIVersionRequest(version) >=
 2222                 api_version.APIVersionRequest('2.13')):
 2223             expected_access['access_key'] = None
 2224         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
 2225         self.mock_object(share_api.API, 'allow_access',
 2226                          mock.Mock(return_value=updated_access))
 2227         body = {key: access}
 2228 
 2229         access = method(req, share['id'], body)
 2230 
 2231         self.assertEqual(expected_access, access['access'])
 2232         share_api.API.allow_access.assert_called_once_with(
 2233             req.environ['manila.context'], share, 'user',
 2234             'clemsontigers', 'rw', None)
 2235 
 2236     @ddt.data(*itertools.product(
 2237         set(['2.28', api_version._MAX_API_VERSION]),
 2238         (constants.SHARE_INSTANCE_RULES_ERROR,
 2239          constants.SHARE_INSTANCE_RULES_SYNCING, constants.STATUS_ACTIVE)))
 2240     @ddt.unpack
 2241     def test_allow_access_access_rules_status_dont_care(self, version, status):
 2242         access = {
 2243             'access_type': 'user',
 2244             'access_to': 'clemsontigers',
 2245             'access_level': 'rw',
 2246         }
 2247         updated_access = db_utils.create_access(**access)
 2248         expected_access = access
 2249         expected_access.update(
 2250             {
 2251                 'id': updated_access['id'],
 2252                 'state': updated_access['state'],
 2253                 'share_id': updated_access['share_id'],
 2254                 'access_key': None,
 2255             })
 2256 
 2257         share = db_utils.create_share(access_rules_status=status)
 2258         req = fakes.HTTPRequest.blank(
 2259             '/v2/shares/%s/action' % share['id'], version=version)
 2260         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
 2261         self.mock_object(share_api.API, 'allow_access',
 2262                          mock.Mock(return_value=updated_access))
 2263         body = {'allow_access': access}
 2264 
 2265         access = self.controller.allow_access(req, share['id'], body)
 2266 
 2267         if api_version.APIVersionRequest(version) >= (
 2268                 api_version.APIVersionRequest("2.33")):
 2269             expected_access.update(
 2270                 {
 2271                     'created_at': updated_access['created_at'],
 2272                     'updated_at': updated_access['updated_at'],
 2273                 })
 2274 
 2275         if api_version.APIVersionRequest(version) >= (
 2276                 api_version.APIVersionRequest("2.45")):
 2277             expected_access.update(
 2278                 {
 2279                     'metadata': {},
 2280                 })
 2281         self.assertEqual(expected_access, access['access'])
 2282         share_api.API.allow_access.assert_called_once_with(
 2283             req.environ['manila.context'], share, 'user',
 2284             'clemsontigers', 'rw', None)
 2285 
 2286     def test_deny_access(self):
 2287         def _stub_deny_access(*args, **kwargs):
 2288             pass
 2289 
 2290         self.mock_object(share_api.API, "deny_access", _stub_deny_access)
 2291         self.mock_object(share_api.API, "access_get", _fake_access_get)
 2292 
 2293         id = 'fake_share_id'
 2294         body = {"os-deny_access": {"access_id": 'fake_acces_id'}}
 2295         req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id)
 2296         res = self.controller._deny_access(req, id, body)
 2297         self.assertEqual(202, res.status_int)
 2298 
 2299     def test_deny_access_not_found(self):
 2300         def _stub_deny_access(*args, **kwargs):
 2301             pass
 2302 
 2303         self.mock_object(share_api.API, "deny_access", _stub_deny_access)
 2304         self.mock_object(share_api.API, "access_get", _fake_access_get)
 2305 
 2306         id = 'super_fake_share_id'
 2307         body = {"os-deny_access": {"access_id": 'fake_acces_id'}}
 2308         req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id)
 2309         self.assertRaises(webob.exc.HTTPNotFound,
 2310                           self.controller._deny_access,
 2311                           req,
 2312                           id,
 2313                           body)
 2314 
 2315     def test_access_list(self):
 2316         fake_access_list = [
 2317             {
 2318                 "state": "fakestatus",
 2319                 "id": "fake_access_id",
 2320                 "access_type": "fakeip",
 2321                 "access_to": "127.0.0.1",
 2322             }
 2323         ]
 2324         self.mock_object(self.controller._access_view_builder, 'list_view',
 2325                          mock.Mock(return_value={'access_list':
 2326                                                  fake_access_list}))
 2327         id = 'fake_share_id'
 2328         body = {"os-access_list": None}
 2329         req = fakes.HTTPRequest.blank('/v2/tenant1/shares/%s/action' % id)
 2330 
 2331         res_dict = self.controller._access_list(req, id, body)
 2332         self.assertEqual({'access_list': fake_access_list}, res_dict)
 2333 
 2334     @ddt.unpack
 2335     @ddt.data(
 2336         {'body': {'os-extend': {'new_size': 2}}, 'version': '2.6'},
 2337         {'body': {'extend': {'new_size': 2}}, 'version': '2.7'},
 2338     )
 2339     def test_extend(self, body, version):
 2340         id = 'fake_share_id'
 2341         share = stubs.stub_share_get(None, None, id)
 2342         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
 2343         self.mock_object(share_api.API, "extend")
 2344 
 2345         size = '2'
 2346         req = fakes.HTTPRequest.blank(
 2347             '/v2/shares/%s/action' % id, version=version)
 2348         actual_response = self.controller._extend(req, id, body)
 2349 
 2350         share_api.API.get.assert_called_once_with(mock.ANY, id)
 2351         share_api.API.extend.assert_called_once_with(
 2352             mock.ANY, share, int(size))
 2353         self.assertEqual(202, actual_response.status_int)
 2354 
 2355     @ddt.data({"os-extend": ""},
 2356               {"os-extend": {"new_size": "foo"}},
 2357               {"os-extend": {"new_size": {'foo': 'bar'}}})
 2358     def test_extend_invalid_body(self, body):
 2359         id = 'fake_share_id'
 2360         req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id)
 2361 
 2362         self.assertRaises(webob.exc.HTTPBadRequest,
 2363                           self.controller._extend, req, id, body)
 2364 
 2365     @ddt.data({'source': exception.InvalidInput,
 2366                'target': webob.exc.HTTPBadRequest},
 2367               {'source': exception.InvalidShare,
 2368                'target': webob.exc.HTTPBadRequest},
 2369               {'source': exception.ShareSizeExceedsAvailableQuota,
 2370                'target': webob.exc.HTTPForbidden})
 2371     @ddt.unpack
 2372     def test_extend_exception(self, source, target):
 2373         id = 'fake_share_id'
 2374         req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id)
 2375         body = {"os-extend": {'new_size': '123'}}
 2376         self.mock_object(share_api.API, "extend",
 2377                          mock.Mock(side_effect=source('fake')))
 2378 
 2379         self.assertRaises(target, self.controller._extend, req, id, body)
 2380 
 2381     @ddt.unpack
 2382     @ddt.data(
 2383         {'body': {'os-shrink': {'new_size': 1}}, 'version': '2.6'},
 2384         {'body': {'shrink': {'new_size': 1}}, 'version': '2.7'},
 2385     )
 2386     def test_shrink(self, body, version):
 2387         id = 'fake_share_id'
 2388         share = stubs.stub_share_get(None, None, id)
 2389         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
 2390         self.mock_object(share_api.API, "shrink")
 2391 
 2392         size = '1'
 2393         req = fakes.HTTPRequest.blank(
 2394             '/v2/shares/%s/action' % id, version=version)
 2395         actual_response = self.controller._shrink(req, id, body)
 2396 
 2397         share_api.API.get.assert_called_once_with(mock.ANY, id)
 2398         share_api.API.shrink.assert_called_once_with(
 2399             mock.ANY, share, int(size))
 2400         self.assertEqual(202, actual_response.status_int)
 2401 
 2402     @ddt.data({"os-shrink": ""},
 2403               {"os-shrink": {"new_size": "foo"}},
 2404               {"os-shrink": {"new_size": {'foo': 'bar'}}})
 2405     def test_shrink_invalid_body(self, body):
 2406         id = 'fake_share_id'
 2407         req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id)
 2408 
 2409         self.assertRaises(webob.exc.HTTPBadRequest,
 2410                           self.controller._shrink, req, id, body)
 2411 
 2412     @ddt.data({'source': exception.InvalidInput,
 2413                'target': webob.exc.HTTPBadRequest},
 2414               {'source': exception.InvalidShare,
 2415                'target': webob.exc.HTTPBadRequest})
 2416     @ddt.unpack
 2417     def test_shrink_exception(self, source, target):
 2418         id = 'fake_share_id'
 2419         req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id)
 2420         body = {"os-shrink": {'new_size': '123'}}
 2421         self.mock_object(share_api.API, "shrink",
 2422                          mock.Mock(side_effect=source('fake')))
 2423 
 2424         self.assertRaises(target, self.controller._shrink, req, id, body)
 2425 
 2426 
 2427 @ddt.ddt
 2428 class ShareAdminActionsAPITest(test.TestCase):
 2429 
 2430     def setUp(self):
 2431         super(ShareAdminActionsAPITest, self).setUp()
 2432         CONF.set_default("default_share_type", None)
 2433         self.flags(transport_url='rabbit://fake:fake@mqhost:5672')
 2434         self.share_api = share_api.API()
 2435         self.admin_context = context.RequestContext('admin', 'fake', True)
 2436         self.member_context = context.RequestContext('fake', 'fake')
 2437 
 2438     def _get_context(self, role):
 2439         return getattr(self, '%s_context' % role)
 2440 
 2441     def _setup_share_data(self, share=None, version='2.7'):
 2442         if share is None:
 2443             share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
 2444                                           size='1',
 2445                                           override_defaults=True)
 2446         path = '/v2/fake/shares/%s/action' % share['id']
 2447         req = fakes.HTTPRequest.blank(path, script_name=path, version=version)
 2448         return share, req
 2449 
 2450     def _reset_status(self, ctxt, model, req, db_access_method,
 2451                       valid_code, valid_status=None, body=None, version='2.7'):
 2452         if float(version) > 2.6:
 2453             action_name = 'reset_status'
 2454         else:
 2455             action_name = 'os-reset_status'
 2456         if body is None:
 2457             body = {action_name: {'status': constants.STATUS_ERROR}}
 2458         req.method = 'POST'
 2459         req.headers['content-type'] = 'application/json'
 2460         req.headers['X-Openstack-Manila-Api-Version'] = version
 2461         req.body = six.b(jsonutils.dumps(body))
 2462         req.environ['manila.context'] = ctxt
 2463 
 2464         resp = req.get_response(fakes.app())
 2465 
 2466         # validate response code and model status
 2467         self.assertEqual(valid_code, resp.status_int)
 2468 
 2469         if valid_code == 404:
 2470             self.assertRaises(exception.NotFound,
 2471                               db_access_method,
 2472                               ctxt,
 2473                               model['id'])
 2474         else:
 2475             actual_model = db_access_method(ctxt, model['id'])
 2476             self.assertEqual(valid_status, actual_model['status'])
 2477 
 2478     @ddt.data(*fakes.fixture_reset_status_with_different_roles)
 2479     @ddt.unpack
 2480     def test_share_reset_status_with_different_roles(self, role, valid_code,
 2481                                                      valid_status, version):
 2482         share, req = self._setup_share_data(version=version)
 2483         ctxt = self._get_context(role)
 2484 
 2485         self._reset_status(ctxt, share, req, db.share_get, valid_code,
 2486                            valid_status, version=version)
 2487 
 2488     @ddt.data(*fakes.fixture_invalid_reset_status_body)
 2489     def test_share_invalid_reset_status_body(self, body):
 2490         share, req = self._setup_share_data(version='2.6')
 2491         ctxt = self.admin_context
 2492 
 2493         self._reset_status(ctxt, share, req, db.share_get, 400,
 2494                            constants.STATUS_AVAILABLE, body, version='2.6')
 2495 
 2496     @ddt.data('2.6', '2.7')
 2497     def test_share_reset_status_for_missing(self, version):
 2498         fake_share = {'id': 'missing-share-id'}
 2499         req = fakes.HTTPRequest.blank(
 2500             '/v2/fake/shares/%s/action' % fake_share['id'], version=version)
 2501 
 2502         self._reset_status(self.admin_context, fake_share, req,
 2503                            db.share_snapshot_get, 404, version=version)
 2504 
 2505     def _force_delete(self, ctxt, model, req, db_access_method, valid_code,
 2506                       check_model_in_db=False, version='2.7'):
 2507         if float(version) > 2.6:
 2508             action_name = 'force_delete'
 2509         else:
 2510             action_name = 'os-force_delete'
 2511         req.method = 'POST'
 2512         req.headers['content-type'] = 'application/json'
 2513         req.headers['X-Openstack-Manila-Api-Version'] = version
 2514         req.body = six.b(jsonutils.dumps({action_name: {}}))
 2515         req.environ['manila.context'] = ctxt
 2516 
 2517         resp = req.get_response(fakes.app())
 2518 
 2519         # validate response
 2520         self.assertEqual(valid_code, resp.status_int)
 2521 
 2522         if valid_code == 202 and check_model_in_db:
 2523             self.assertRaises(exception.NotFound,
 2524                               db_access_method,
 2525                               ctxt,
 2526                               model['id'])
 2527 
 2528     @ddt.data(*fakes.fixture_force_delete_with_different_roles)
 2529     @ddt.unpack
 2530     def test_share_force_delete_with_different_roles(self, role, resp_code,
 2531                                                      version):
 2532         share, req = self._setup_share_data(version=version)
 2533         ctxt = self._get_context(role)
 2534 
 2535         self._force_delete(ctxt, share, req, db.share_get, resp_code,
 2536                            check_model_in_db=True, version=version)
 2537 
 2538     @ddt.data('2.6', '2.7')
 2539     def test_share_force_delete_missing(self, version):
 2540         share, req = self._setup_share_data(
 2541             share={'id': 'fake'}, version=version)
 2542         ctxt = self._get_context('admin')
 2543 
 2544         self._force_delete(
 2545             ctxt, share, req, db.share_get, 404, version=version)
 2546 
 2547 
 2548 @ddt.ddt
 2549 class ShareUnmanageTest(test.TestCase):
 2550 
 2551     def setUp(self):
 2552         super(ShareUnmanageTest, self).setUp()
 2553         self.controller = shares.ShareController()
 2554         self.mock_object(share_api.API, 'get_all',
 2555                          stubs.stub_get_all_shares)
 2556         self.mock_object(share_api.API, 'get',
 2557                          stubs.stub_share_get)
 2558         self.mock_object(share_api.API, 'update', stubs.stub_share_update)
 2559         self.mock_object(share_api.API, 'delete', stubs.stub_share_delete)
 2560         self.mock_object(share_api.API, 'get_snapshot',
 2561                          stubs.stub_snapshot_get)
 2562         self.share_id = 'fake'
 2563         self.request = fakes.HTTPRequest.blank(
 2564             '/share/%s/unmanage' % self.share_id,
 2565             use_admin_context=True, version='2.7',
 2566         )
 2567 
 2568     def test_unmanage_share(self):
 2569         share = dict(status=constants.STATUS_AVAILABLE, id='foo_id',
 2570                      instance={})
 2571         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
 2572         self.mock_object(share_api.API, 'unmanage', mock.Mock())
 2573         self.mock_object(
 2574             self.controller.share_api.db, 'share_snapshot_get_all_for_share',
 2575             mock.Mock(return_value=[]))
 2576 
 2577         actual_result = self.controller.unmanage(self.request, share['id'])
 2578 
 2579         self.assertEqual(202, actual_result.status_int)
 2580         (self.controller.share_api.db.share_snapshot_get_all_for_share.
 2581             assert_called_once_with(
 2582                 self.request.environ['manila.context'], share['id']))
 2583         self.controller.share_api.get.assert_called_once_with(
 2584             self.request.environ['manila.context'], share['id'])
 2585         share_api.API.unmanage.assert_called_once_with(
 2586             self.request.environ['manila.context'], share)
 2587 
 2588     def test__unmanage(self):
 2589         body = {}
 2590         req = fakes.HTTPRequest.blank(
 2591             '/shares/1/action', use_admin_context=False, version='2.49')
 2592         share = dict(status=constants.STATUS_AVAILABLE, id='foo_id',
 2593                      instance={})
 2594         mock_unmanage = self.mock_object(self.controller, '_unmanage')
 2595 
 2596         self.controller.unmanage(req, share['id'], body)
 2597 
 2598         mock_unmanage.assert_called_once_with(
 2599             req, share['id'], body, allow_dhss_true=True
 2600         )
 2601 
 2602     def test_unmanage_share_that_has_snapshots(self):
 2603         share = dict(status=constants.STATUS_AVAILABLE, id='foo_id',
 2604                      instance={})
 2605         snapshots = ['foo', 'bar']
 2606         self.mock_object(self.controller.share_api, 'unmanage')
 2607         self.mock_object(
 2608             self.controller.share_api.db, 'share_snapshot_get_all_for_share',
 2609             mock.Mock(return_value=snapshots))
 2610         self.mock_object(
 2611             self.controller.share_api, 'get',
 2612             mock.Mock(return_value=share))
 2613 
 2614         self.assertRaises(
 2615             webob.exc.HTTPForbidden,
 2616             self.controller.unmanage, self.request, share['id'])
 2617 
 2618         self.assertFalse(self.controller.share_api.unmanage.called)
 2619         (self.controller.share_api.db.share_snapshot_get_all_for_share.
 2620             assert_called_once_with(
 2621                 self.request.environ['manila.context'], share['id']))
 2622         self.controller.share_api.get.assert_called_once_with(
 2623             self.request.environ['manila.context'], share['id'])
 2624 
 2625     def test_unmanage_share_based_on_share_server(self):
 2626         share = dict(instance=dict(share_server_id='foo_id'), id='bar_id')
 2627         self.mock_object(
 2628             self.controller.share_api, 'get',
 2629             mock.Mock(return_value=share))
 2630 
 2631         self.assertRaises(
 2632             webob.exc.HTTPForbidden,
 2633             self.controller.unmanage, self.request, share['id'])
 2634 
 2635         self.controller.share_api.get.assert_called_once_with(
 2636             self.request.environ['manila.context'], share['id'])
 2637 
 2638     @ddt.data(*constants.TRANSITIONAL_STATUSES)
 2639     def test_unmanage_share_with_transitional_state(self, share_status):
 2640         share = dict(status=share_status, id='foo_id', instance={})
 2641         self.mock_object(
 2642             self.controller.share_api, 'get',
 2643             mock.Mock(return_value=share))
 2644 
 2645         self.assertRaises(
 2646             webob.exc.HTTPForbidden,
 2647             self.controller.unmanage, self.request, share['id'])
 2648 
 2649         self.controller.share_api.get.assert_called_once_with(
 2650             self.request.environ['manila.context'], share['id'])
 2651 
 2652     def test_unmanage_share_not_found(self):
 2653         self.mock_object(share_api.API, 'get', mock.Mock(
 2654             side_effect=exception.NotFound))
 2655         self.mock_object(share_api.API, 'unmanage', mock.Mock())
 2656 
 2657         self.assertRaises(webob.exc.HTTPNotFound,
 2658                           self.controller.unmanage,
 2659                           self.request, self.share_id)
 2660 
 2661     @ddt.data(exception.InvalidShare(reason="fake"),
 2662               exception.PolicyNotAuthorized(action="fake"),)
 2663     def test_unmanage_share_invalid(self, side_effect):
 2664         share = dict(status=constants.STATUS_AVAILABLE, id='foo_id',
 2665                      instance={})
 2666         self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
 2667         self.mock_object(share_api.API, 'unmanage', mock.Mock(
 2668             side_effect=side_effect))
 2669 
 2670         self.assertRaises(webob.exc.HTTPForbidden,
 2671                           self.controller.unmanage,
 2672                           self.request, self.share_id)
 2673 
 2674     def test_wrong_permissions(self):
 2675         share_id = 'fake'
 2676         req = fakes.HTTPRequest.blank('/share/%s/unmanage' % share_id,
 2677                                       use_admin_context=False, version='2.7')
 2678 
 2679         self.assertRaises(webob.exc.HTTPForbidden,
 2680                           self.controller.unmanage,
 2681                           req,
 2682                           share_id)
 2683 
 2684     def test_unsupported_version(self):
 2685         share_id = 'fake'
 2686         req = fakes.HTTPRequest.blank('/share/%s/unmanage' % share_id,
 2687                                       use_admin_context=False, version='2.6')
 2688 
 2689         self.assertRaises(exception.VersionNotFoundForAPIMethod,
 2690                           self.controller.unmanage,
 2691                           req,
 2692                           share_id)
 2693 
 2694 
 2695 def get_fake_manage_body(export_path='/fake', service_host='fake@host#POOL',
 2696                          protocol='fake', share_type='fake', **kwargs):
 2697     fake_share = {
 2698         'export_path': export_path,
 2699         'service_host': service_host,
 2700         'protocol': protocol,
 2701         'share_type': share_type,
 2702     }
 2703     fake_share.update(kwargs)
 2704     return {'share': fake_share}
 2705 
 2706 
 2707 @ddt.ddt
 2708 class ShareManageTest(test.TestCase):
 2709 
 2710     def setUp(self):
 2711         super(ShareManageTest, self).setUp()
 2712         self.controller = shares.ShareController()
 2713         self.resource_name = self.controller.resource_name
 2714         self.request = fakes.HTTPRequest.blank(
 2715             '/v2/shares/manage', use_admin_context=True, version='2.7')
 2716         self.mock_policy_check = self.mock_object(
 2717             policy, 'check_policy', mock.Mock(return_value=True))
 2718 
 2719     def _setup_manage_mocks(self, service_is_up=True):
 2720         self.mock_object(db, 'service_get_by_host_and_topic', mock.Mock(
 2721             return_value={'host': 'fake'}))
 2722         self.mock_object(share_types, 'get_share_type_by_name_or_id',
 2723                          mock.Mock(return_value={'id': 'fake'}))
 2724         self.mock_object(utils, 'service_is_up', mock.Mock(
 2725             return_value=service_is_up))
 2726         if service_is_up:
 2727             self.mock_object(utils, 'validate_service_host')
 2728         else:
 2729             self.mock_object(
 2730                 utils,
 2731                 'validate_service_host',
 2732                 mock.Mock(side_effect=exception.ServiceIsDown(service='fake')))
 2733 
 2734     def test__manage(self):
 2735         body = {}
 2736         req = fakes.HTTPRequest.blank(
 2737             '/v2/shares/manage', use_admin_context=True, version='2.49')
 2738         mock_manage = self.mock_object(self.controller, '_manage')
 2739 
 2740         self.controller.manage(req, body)
 2741 
 2742         mock_manage.assert_called_once_with(
 2743             req, body, allow_dhss_true=True
 2744         )
 2745 
 2746     @ddt.data({},
 2747               {'shares': {}},
 2748               {'share': get_fake_manage_body('', None, None)})
 2749     def test_share_manage_invalid_body(self, body):
 2750         self.assertRaises(webob.exc.HTTPUnprocessableEntity,
 2751                           self.controller.manage,
 2752                           self.request,
 2753                           body)
 2754 
 2755     def test_share_manage_service_not_found(self):
 2756         body = get_fake_manage_body()
 2757         self.mock_object(db, 'service_get_by_host_and_topic', mock.Mock(
 2758             side_effect=exception.ServiceNotFound(service_id='fake')))
 2759 
 2760         self.assertRaises(webob.exc.HTTPNotFound,
 2761                           self.controller.manage,
 2762                           self.request,
 2763                           body)
 2764 
 2765     def test_share_manage_share_type_not_found(self):
 2766         body = get_fake_manage_body()
 2767         self.mock_object(db, 'service_get_by_host_and_topic', mock.Mock())
 2768         self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
 2769         self.mock_object(db, 'share_type_get_by_name', mock.Mock(
 2770             side_effect=exception.ShareTypeNotFoundByName(
 2771                 share_type_name='fake')))
 2772 
 2773         self.assertRaises(webob.exc.HTTPNotFound,
 2774                           self.controller.manage,
 2775                           self.request,
 2776                           body)
 2777 
 2778     @ddt.data({'service_is_up': False, 'service_host': 'fake@host#POOL'},
 2779               {'service_is_up': True, 'service_host': 'fake@host'})
 2780     def test_share_manage_bad_request(self, settings):
 2781         body = get_fake_manage_body(service_host=settings.pop('service_host'))
 2782         self._setup_manage_mocks(**settings)
 2783 
 2784         self.assertRaises(webob.exc.HTTPBadRequest,
 2785                           self.controller.manage,
 2786                           self.request,
 2787                           body)
 2788 
 2789     def test_share_manage_duplicate_share(self):
 2790         body = get_fake_manage_body()
 2791         exc = exception.InvalidShare(reason="fake")
 2792         self._setup_manage_mocks()
 2793         self.mock_object(share_api.API, 'manage', mock.Mock(side_effect=exc))
 2794 
 2795         self.assertRaises(webob.exc.HTTPConflict,
 2796                           self.controller.manage,
 2797                           self.request,
 2798                           body)
 2799 
 2800     def test_share_manage_forbidden_manage(self):
 2801         body = get_fake_manage_body()
 2802         self._setup_manage_mocks()
 2803         error = mock.Mock(side_effect=exception.PolicyNotAuthorized(action=''))
 2804         self.mock_object(share_api.API, 'manage', error)
 2805 
 2806         self.assertRaises(webob.exc.HTTPForbidden,
 2807                           self.controller.manage,
 2808                           self.request,
 2809                           body)
 2810 
 2811     def test_share_manage_forbidden_validate_service_host(self):
 2812         body = get_fake_manage_body()
 2813         self._setup_manage_mocks()
 2814         error = mock.Mock(side_effect=exception.PolicyNotAuthorized(action=''))
 2815         self.mock_object(
 2816             utils, 'validate_service_host', mock.Mock(side_effect=error))
 2817 
 2818         self.assertRaises(webob.exc.HTTPForbidden,
 2819                           self.controller.manage,
 2820                           self.request,
 2821                           body)
 2822 
 2823     @ddt.data(
 2824         get_fake_manage_body(name='foo', description='bar'),
 2825         get_fake_manage_body(display_name='foo', description='bar'),
 2826         get_fake_manage_body(name='foo', display_description='bar'),
 2827         get_fake_manage_body(display_name='foo', display_description='bar'),
 2828         get_fake_manage_body(display_name='foo', display_description='bar',
 2829                              driver_options=dict(volume_id='quuz')),
 2830     )
 2831     def test_share_manage(self, data):
 2832         self._test_share_manage(data, "2.7")
 2833 
 2834     @ddt.data(
 2835         get_fake_manage_body(name='foo', description='bar', is_public=True),
 2836         get_fake_manage_body(name='foo', description='bar', is_public=False)
 2837     )
 2838     def test_share_manage_with_is_public(self, data):
 2839         self._test_share_manage(data, "2.8")
 2840 
 2841     def test_share_manage_with_user_id(self):
 2842         self._test_share_manage(get_fake_manage_body(
 2843             name='foo', description='bar', is_public=True), "2.16")
 2844 
 2845     def _test_share_manage(self, data, version):
 2846         expected = {
 2847             'share': {
 2848                 'status': 'fakestatus',
 2849                 'description': 'displaydesc',
 2850                 'availability_zone': 'fakeaz',
 2851                 'name': 'displayname',
 2852                 'share_proto': 'FAKEPROTO',
 2853                 'metadata': {},
 2854                 'project_id': 'fakeproject',
 2855                 'host': 'fakehost',
 2856                 'id': 'fake',
 2857                 'snapshot_id': '2',
 2858                 'share_network_id': None,
 2859                 'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
 2860                 'size': 1,
 2861                 'share_type_name': None,
 2862                 'share_server_id': 'fake_share_server_id',
 2863                 'share_type': '1',
 2864                 'volume_type': '1',
 2865                 'is_public': False,
 2866                 'snapshot_support': True,
 2867                 'task_state': None,
 2868                 'links': [
 2869                     {
 2870                         'href': 'http://localhost/v1/fake/shares/fake',
 2871                         'rel': 'self'
 2872                     },
 2873                     {
 2874                         'href': 'http://localhost/fake/shares/fake',
 2875                         'rel': 'bookmark'
 2876                     }
 2877                 ],
 2878             }
 2879         }
 2880         self._setup_manage_mocks()
 2881         return_share = mock.Mock(
 2882             return_value=stubs.stub_share(
 2883                 'fake',
 2884                 instance={
 2885                     'share_type_id': '1',
 2886                 })
 2887             )
 2888         self.mock_object(
 2889             share_api.API, 'manage', return_share)
 2890         self.mock_object(
 2891             common, 'validate_public_share_policy',
 2892             mock.Mock(side_effect=lambda *args, **kwargs: args[1]))
 2893         share = {
 2894             'host': data['share']['service_host'],
 2895             'export_location_path': data['share']['export_path'],
 2896             'share_proto': data['share']['protocol'].upper(),
 2897             'share_type_id': 'fake',
 2898             'display_name': 'foo',
 2899             'display_description': 'bar',
 2900         }
 2901         driver_options = data['share'].get('driver_options', {})
 2902 
 2903         if (api_version.APIVersionRequest(version) <=
 2904                 api_version.APIVersionRequest('2.8')):
 2905             expected['share']['export_location'] = 'fake_location'
 2906             expected['share']['export_locations'] = (
 2907                 ['fake_location', 'fake_location2'])
 2908 
 2909         if (api_version.APIVersionRequest(version) >=
 2910                 api_version.APIVersionRequest('2.10')):
 2911             expected['share']['access_rules_status'] = (
 2912                 constants.STATUS_ACTIVE)
 2913         if (api_version.APIVersionRequest(version) >=
 2914                 api_version.APIVersionRequest('2.11')):
 2915             expected['share']['has_replicas'] = False
 2916             expected['share']['replication_type'] = None
 2917 
 2918         if (api_version.APIVersionRequest(version) >=
 2919                 api_version.APIVersionRequest('2.16')):
 2920             expected['share']['user_id'] = 'fakeuser'
 2921 
 2922         if (api_version.APIVersionRequest(version) >=
 2923                 api_version.APIVersionRequest('2.8')):
 2924             share['is_public'] = data['share']['is_public']
 2925 
 2926         req = fakes.HTTPRequest.blank('/v2/shares/manage', version=version,
 2927                                       use_admin_context=True)
 2928 
 2929         actual_result = self.controller.manage(req, data)
 2930 
 2931         share_api.API.manage.assert_called_once_with(
 2932             mock.ANY, share, driver_options)
 2933 
 2934         self.assertIsNotNone(actual_result)
 2935         self.assertEqual(expected, actual_result)
 2936         self.mock_policy_check.assert_called_once_with(
 2937             req.environ['manila.context'], self.resource_name, 'manage')
 2938 
 2939     def test_wrong_permissions(self):
 2940         body = get_fake_manage_body()
 2941 
 2942         self.assertRaises(
 2943             webob.exc.HTTPForbidden,
 2944             self.controller.manage,
 2945             fakes.HTTPRequest.blank(
 2946                 '/share/manage', use_admin_context=False, version='2.7'),
 2947             body,
 2948         )
 2949 
 2950     def test_unsupported_version(self):
 2951         share_id = 'fake'
 2952         req = fakes.HTTPRequest.blank(
 2953             '/share/manage', use_admin_context=False, version='2.6')
 2954 
 2955         self.assertRaises(exception.VersionNotFoundForAPIMethod,
 2956                           self.controller.manage,
 2957                           req,
 2958                           share_id)
 2959 
 2960     def test_revert(self):
 2961 
 2962         mock_revert = self.mock_object(
 2963             self.controller, '_revert',
 2964             mock.Mock(return_value='fake_response'))
 2965         req = fakes.HTTPRequest.blank(
 2966             '/shares/fake_id/action', use_admin_context=False, version='2.27')
 2967 
 2968         result = self.controller.revert(req, 'fake_id', 'fake_body')
 2969 
 2970         self.assertEqual('fake_response', result)
 2971         mock_revert.assert_called_once_with(
 2972             req, 'fake_id', 'fake_body')
 2973 
 2974     def test_revert_unsupported(self):
 2975 
 2976         req = fakes.HTTPRequest.blank(
 2977             '/shares/fake_id/action', use_admin_context=False, version='2.24')
 2978 
 2979         self.assertRaises(exception.VersionNotFoundForAPIMethod,
 2980                           self.controller.revert,
 2981                           req,
 2982                           'fake_id',
 2983                           'fake_body')