"Fossies" - the Fresh Open Source Software Archive

Member "horizon-14.0.4/openstack_dashboard/test/unit/api/rest/test_nova.py" (22 Oct 2019, 48139 Bytes) of package /linux/misc/openstack/horizon-14.0.4.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.

    1 # Copyright 2014, Rackspace, US, Inc.
    2 #
    3 # Licensed under the Apache License, Version 2.0 (the "License");
    4 # you may not use this file except in compliance with the License.
    5 # You may obtain a copy of the License at
    6 #
    7 #    http://www.apache.org/licenses/LICENSE-2.0
    8 #
    9 # Unless required by applicable law or agreed to in writing, software
   10 # distributed under the License is distributed on an "AS IS" BASIS,
   11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12 # See the License for the specific language governing permissions and
   13 # limitations under the License.
   14 
   15 import json
   16 from json import loads as to_json
   17 import uuid
   18 
   19 from django.conf import settings
   20 import mock
   21 
   22 from openstack_dashboard import api
   23 from openstack_dashboard.api.base import Quota
   24 from openstack_dashboard.api.rest import nova
   25 from openstack_dashboard.test import helpers as test
   26 from openstack_dashboard.usage import quotas
   27 
   28 
   29 # NOTE(flwang): mock.Mock and mock.MagicMock do not support sort, so the test
   30 # case involved sorted will fail. This fake class is for the flavor test cases
   31 # related to sort.
   32 class FakeFlavor(object):
   33     def __init__(self, id, ram=1):
   34         self.id = id
   35         self.ram = ram
   36         self.extras = {}
   37 
   38     def to_dict(self):
   39         return {"id": self.id}
   40 
   41 
   42 class NovaRestTestCase(test.TestCase):
   43 
   44     #
   45     # Snapshots
   46     #
   47     @test.create_mocks({api.nova: ['snapshot_create']})
   48     def test_snapshots_create(self):
   49         body = '{"instance_id": "1234", "name": "foo"}'
   50         request = self.mock_rest_request(body=body)
   51         self.mock_snapshot_create.return_value = {'id': 'abcd', 'name': 'foo'}
   52         response = nova.Snapshots().post(request)
   53         self.assertStatusCode(response, 200)
   54         self.assertEqual(response.json, {'id': 'abcd', 'name': 'foo'})
   55         self.mock_snapshot_create.assert_called_once_with(request,
   56                                                           instance_id='1234',
   57                                                           name='foo')
   58 
   59     #
   60     # Server Actions
   61     #
   62     @test.create_mocks({api.nova: ['instance_action_list']})
   63     def test_serveractions_list(self):
   64         request = self.mock_rest_request()
   65         self.mock_instance_action_list.return_value = [
   66             mock.Mock(**{'to_dict.return_value': {'id': '1'}}),
   67             mock.Mock(**{'to_dict.return_value': {'id': '2'}}),
   68         ]
   69         response = nova.ServerActions().get(request, 'MegaMan')
   70         self.assertStatusCode(response, 200)
   71         self.assertEqual(response.json, {'items': [{'id': '1'}, {'id': '2'}]})
   72         self.mock_instance_action_list.assert_called_once_with(request,
   73                                                                'MegaMan')
   74 
   75     @test.create_mocks({api.nova: ['server_start']})
   76     def test_server_start(self):
   77         self.mock_server_start.return_value = None
   78         request = self.mock_rest_request(body='{"operation": "start"}')
   79         response = nova.Server().post(request, 'MegaMan')
   80         self.assertStatusCode(response, 204)
   81         self.mock_server_start.assert_called_once_with(request, 'MegaMan')
   82 
   83     @test.create_mocks({api.nova: ['server_stop']})
   84     def test_server_stop(self):
   85         self.mock_server_stop.return_value = None
   86         request = self.mock_rest_request(body='{"operation": "stop"}')
   87         response = nova.Server().post(request, 'MegaMan')
   88         self.assertStatusCode(response, 204)
   89         self.mock_server_stop.assert_called_once_with(request, 'MegaMan')
   90 
   91     @test.create_mocks({api.nova: ['server_pause']})
   92     def test_server_pause(self):
   93         self.mock_server_pause.return_value = None
   94         request = self.mock_rest_request(body='{"operation": "pause"}')
   95         response = nova.Server().post(request, 'MegaMan')
   96         self.assertStatusCode(response, 204)
   97         self.mock_server_pause.assert_called_once_with(request, 'MegaMan')
   98 
   99     @test.create_mocks({api.nova: ['server_unpause']})
  100     def test_server_unpause(self):
  101         self.mock_server_unpause.return_value = None
  102         request = self.mock_rest_request(body='{"operation": "unpause"}')
  103         response = nova.Server().post(request, 'MegaMan')
  104         self.assertStatusCode(response, 204)
  105         self.mock_server_unpause.assert_called_once_with(request, 'MegaMan')
  106 
  107     @test.create_mocks({api.nova: ['server_suspend']})
  108     def test_server_suspend(self):
  109         self.mock_server_suspend.return_value = None
  110         request = self.mock_rest_request(body='{"operation": "suspend"}')
  111         response = nova.Server().post(request, 'MegaMan')
  112         self.assertStatusCode(response, 204)
  113         self.mock_server_suspend.assert_called_once_with(request, 'MegaMan')
  114 
  115     @test.create_mocks({api.nova: ['server_resume']})
  116     def test_server_resume(self):
  117         self.mock_server_resume.return_value = None
  118         request = self.mock_rest_request(body='{"operation": "resume"}')
  119         response = nova.Server().post(request, 'MegaMan')
  120         self.assertStatusCode(response, 204)
  121         self.mock_server_resume.assert_called_once_with(request, 'MegaMan')
  122 
  123     @test.create_mocks({api.nova: ['server_reboot']})
  124     def test_server_hard_reboot(self):
  125         self.mock_server_reboot.return_value = None
  126         request = self.mock_rest_request(body='{"operation": "hard_reboot"}')
  127         response = nova.Server().post(request, 'MegaMan')
  128         self.assertStatusCode(response, 204)
  129         self.mock_server_reboot.assert_called_once_with(request, 'MegaMan',
  130                                                         False)
  131 
  132     @test.create_mocks({api.nova: ['server_reboot']})
  133     def test_server_soft_reboot(self):
  134         self.mock_server_reboot.return_value = None
  135         request = self.mock_rest_request(body='{"operation": "soft_reboot"}')
  136         response = nova.Server().post(request, 'MegaMan')
  137         self.assertStatusCode(response, 204)
  138         self.mock_server_reboot.assert_called_once_with(request, 'MegaMan',
  139                                                         True)
  140 
  141     #
  142     # Security Groups
  143     #
  144     @test.create_mocks({api.neutron: ['server_security_groups']})
  145     def test_securitygroups_list(self):
  146         request = self.mock_rest_request()
  147         self.mock_server_security_groups.return_value = [
  148             mock.Mock(**{'to_dict.return_value': {'id': '1'}}),
  149             mock.Mock(**{'to_dict.return_value': {'id': '2'}}),
  150         ]
  151         response = nova.SecurityGroups().get(request, 'MegaMan')
  152         self.assertStatusCode(response, 200)
  153         self.assertEqual(response.json, {'items': [{'id': '1'}, {'id': '2'}]})
  154         self.mock_server_security_groups.assert_called_once_with(request,
  155                                                                  'MegaMan')
  156 
  157     #
  158     # Console Output
  159     #
  160     @test.create_mocks({api.nova: ['server_console_output']})
  161     def test_console_output(self):
  162         request = self.mock_rest_request(body='{"length": 50}')
  163         self.mock_server_console_output.return_value = "this\nis\ncool"
  164         response = nova.ConsoleOutput().post(request, 'MegaMan')
  165         self.assertStatusCode(response, 200)
  166         self.assertEqual(response.json, {'lines': ["this", "is", "cool"]})
  167         self.mock_server_console_output.assert_called_once_with(request,
  168                                                                 'MegaMan',
  169                                                                 tail_length=50)
  170 
  171     #
  172     # Remote Console Info
  173     #
  174     @test.create_mocks({api.nova: ['server_serial_console']})
  175     def test_console_info(self):
  176         request = self.mock_rest_request(body='{"console_type": "SERIAL"}')
  177         retval = mock.Mock(**{"url": "http://here.com"})
  178         self.mock_server_serial_console.return_value = retval
  179         response = nova.RemoteConsoleInfo().post(request, 'MegaMan')
  180         self.assertStatusCode(response, 200)
  181         self.assertEqual(response.json,
  182                          {"type": "SERIAL", "url": "http://here.com"})
  183         self.mock_server_serial_console.assert_called_once_with(request,
  184                                                                 'MegaMan')
  185 
  186     #
  187     # Volumes
  188     #
  189     @test.create_mocks({api.nova: ['instance_volumes_list']})
  190     def test_volumes_list(self):
  191         request = self.mock_rest_request()
  192         self.mock_instance_volumes_list.return_value = [
  193             mock.Mock(**{'to_dict.return_value': {'id': '1'}}),
  194             mock.Mock(**{'to_dict.return_value': {'id': '2'}}),
  195         ]
  196         response = nova.Volumes().get(request, 'MegaMan')
  197         self.assertStatusCode(response, 200)
  198         self.assertEqual(response.json, {'items': [{'id': '1'}, {'id': '2'}]})
  199         self.mock_instance_volumes_list.assert_called_once_with(request,
  200                                                                 'MegaMan')
  201 
  202     #
  203     # Keypairs
  204     #
  205     @test.create_mocks({api.nova: ['keypair_list']})
  206     def test_keypair_list(self):
  207         request = self.mock_rest_request()
  208         self.mock_keypair_list.return_value = [
  209             mock.Mock(**{'to_dict.return_value': {'id': 'one'}}),
  210             mock.Mock(**{'to_dict.return_value': {'id': 'two'}}),
  211         ]
  212         response = nova.Keypairs().get(request)
  213         self.assertStatusCode(response, 200)
  214         self.assertEqual({"items": [{"id": "one"}, {"id": "two"}]},
  215                          response.json)
  216         self.mock_keypair_list.assert_called_once_with(request)
  217 
  218     @test.create_mocks({api.nova: ['keypair_create']})
  219     def test_keypair_create(self):
  220         request = self.mock_rest_request(body='''{"name": "Ni!"}''')
  221         new = self.mock_keypair_create.return_value
  222         new.to_dict.return_value = {'name': 'Ni!', 'public_key': 'sekrit'}
  223         new.name = 'Ni!'
  224         with mock.patch.object(settings, 'DEBUG', True):
  225             response = nova.Keypairs().post(request)
  226         self.assertStatusCode(response, 201)
  227         self.assertEqual({"name": "Ni!", "public_key": "sekrit"},
  228                          response.json)
  229         self.assertEqual('/api/nova/keypairs/Ni%21', response['location'])
  230         self.mock_keypair_create.assert_called_once_with(request, 'Ni!')
  231 
  232     @test.create_mocks({api.nova: ['keypair_import']})
  233     def test_keypair_import(self):
  234         request = self.mock_rest_request(body='''
  235             {"name": "Ni!", "public_key": "hi"}
  236         ''')
  237         new = self.mock_keypair_import.return_value
  238         new.to_dict.return_value = {'name': 'Ni!', 'public_key': 'hi'}
  239         new.name = 'Ni!'
  240         with mock.patch.object(settings, 'DEBUG', True):
  241             response = nova.Keypairs().post(request)
  242         self.assertStatusCode(response, 201)
  243         self.assertEqual({"name": "Ni!", "public_key": "hi"},
  244                          response.json)
  245         self.assertEqual('/api/nova/keypairs/Ni%21', response['location'])
  246         self.mock_keypair_import.assert_called_once_with(request, 'Ni!', 'hi')
  247 
  248     @test.create_mocks({api.nova: ['keypair_get']})
  249     def test_keypair_get(self):
  250         request = self.mock_rest_request()
  251         self.mock_keypair_get.return_value.to_dict.return_value = {'name': '1'}
  252         response = nova.Keypair().get(request, '1')
  253         self.assertStatusCode(response, 200)
  254         self.assertEqual({"name": "1"},
  255                          response.json)
  256         self.mock_keypair_get.assert_called_once_with(request, "1")
  257 
  258     @test.create_mocks({api.nova: ['keypair_delete']})
  259     def test_keypair_delete(self):
  260         self.mock_keypair_delete.return_value = None
  261         request = self.mock_rest_request()
  262         nova.Keypair().delete(request, "1")
  263         self.mock_keypair_delete.assert_called_once_with(request, "1")
  264 
  265     #
  266     # Availability Zones
  267     #
  268     def test_availzone_get_brief(self):
  269         self._test_availzone_get(False)
  270 
  271     def test_availzone_get_detailed(self):
  272         self._test_availzone_get(True)
  273 
  274     @test.create_mocks({api.nova: ['availability_zone_list']})
  275     def _test_availzone_get(self, detail):
  276         if detail:
  277             request = self.mock_rest_request(GET={'detailed': 'true'})
  278         else:
  279             request = self.mock_rest_request(GET={})
  280         self.mock_availability_zone_list.return_value = [
  281             mock.Mock(**{'to_dict.return_value': {'id': 'one'}}),
  282             mock.Mock(**{'to_dict.return_value': {'id': 'two'}}),
  283         ]
  284         response = nova.AvailabilityZones().get(request)
  285         self.assertStatusCode(response, 200)
  286         self.assertEqual({"items": [{"id": "one"}, {"id": "two"}]},
  287                          response.json)
  288         self.mock_availability_zone_list.assert_called_once_with(request,
  289                                                                  detail)
  290 
  291     #
  292     # Limits
  293     #
  294     def test_limits_get_not_reserved(self):
  295         self._test_limits_get(False)
  296 
  297     def test_limits_get_reserved(self):
  298         self._test_limits_get(True)
  299 
  300     @test.create_mocks({api.nova: ['tenant_absolute_limits']})
  301     def _test_limits_get(self, reserved):
  302         if reserved:
  303             request = self.mock_rest_request(GET={'reserved': 'true'})
  304         else:
  305             request = self.mock_rest_request(GET={})
  306         self.mock_tenant_absolute_limits.return_value = {'id': 'one'}
  307         response = nova.Limits().get(request)
  308         self.assertStatusCode(response, 200)
  309         self.mock_tenant_absolute_limits.assert_called_once_with(request,
  310                                                                  reserved)
  311         self.assertEqual({"id": "one"}, response.json)
  312 
  313     #
  314     # Servers
  315     #
  316     def test_server_create_missing(self):
  317         request = self.mock_rest_request(body='''{"name": "hi"}''')
  318         response = nova.Servers().post(request)
  319         self.assertStatusCode(response, 400)
  320         self.assertEqual("missing required parameter 'source_id'",
  321                          response.json)
  322 
  323     @test.create_mocks({api.nova: ['server_create']})
  324     def test_server_create_basic(self):
  325         request = self.mock_rest_request(body='''{"name": "Ni!",
  326             "source_id": "image123", "flavor_id": "flavor123",
  327             "key_name": "sekrit", "user_data": "base64 yes",
  328             "security_groups": [{"name": "root"}]}
  329         ''')
  330         new = self.mock_server_create.return_value
  331         new.to_dict.return_value = {'id': 'server123'}
  332         new.id = 'server123'
  333         response = nova.Servers().post(request)
  334         self.assertStatusCode(response, 201)
  335         self.assertEqual({"id": "server123"}, response.json)
  336         self.assertEqual('/api/nova/servers/server123', response['location'])
  337         self.mock_server_create.assert_called_once_with(
  338             request, 'Ni!', 'image123', 'flavor123', 'sekrit', 'base64 yes',
  339             [{'name': 'root'}]
  340         )
  341 
  342     @test.create_mocks({api.nova: ['server_create']})
  343     def test_server_create_with_leading_trailing_space(self):
  344         request = self.mock_rest_request(body='''{"name": " Ni! ",
  345                 "source_id": "image123", "flavor_id": "flavor123",
  346                 "key_name": "sekrit", "user_data": "base64 yes",
  347                 "security_groups": [{"name": "root"}]}
  348             ''')
  349         new = self.mock_server_create.return_value
  350         new.to_dict.return_value = {'name': ' Ni! '.strip()}
  351         new.id = str(uuid.uuid4())
  352         response = nova.Servers().post(request)
  353         self.assertStatusCode(response, 201)
  354         self.assertEqual({"name": "Ni!"}, response.json)
  355         self.mock_server_create.assert_called_once_with(
  356             request, ' Ni! ', 'image123', 'flavor123', 'sekrit', 'base64 yes',
  357             [{'name': 'root'}])
  358 
  359     @test.create_mocks({api.nova: ['server_list']})
  360     def test_server_list(self):
  361         request = self.mock_rest_request()
  362         self.mock_server_list.return_value = ([
  363             mock.Mock(**{'to_dict.return_value': {'id': 'one'}}),
  364             mock.Mock(**{'to_dict.return_value': {'id': 'two'}}),
  365         ], False)
  366 
  367         response = nova.Servers().get(request)
  368         self.assertStatusCode(response, 200)
  369         self.assertEqual({'items': [{'id': 'one'}, {'id': 'two'}]},
  370                          response.json)
  371         self.mock_server_list.assert_called_once_with(request)
  372 
  373     @test.create_mocks({api.nova: ['server_get']})
  374     def test_server_get_single(self):
  375         request = self.mock_rest_request()
  376         self.mock_server_get.return_value.to_dict.return_value = {'name': '1'}
  377 
  378         response = nova.Server().get(request, "1")
  379         self.assertStatusCode(response, 200)
  380         self.mock_server_get.assert_called_once_with(request, "1")
  381 
  382     #
  383     # Server Groups
  384     #
  385     @test.create_mocks({api.nova: ['server_group_list']})
  386     def test_server_group_list(self):
  387         request = self.mock_rest_request()
  388         self.mock_server_group_list.return_value = [
  389             mock.Mock(**{'to_dict.return_value': {'id': '1'}}),
  390             mock.Mock(**{'to_dict.return_value': {'id': '2'}}),
  391         ]
  392 
  393         response = nova.ServerGroups().get(request)
  394         self.assertStatusCode(response, 200)
  395         self.assertEqual({'items': [{'id': '1'}, {'id': '2'}]},
  396                          response.json)
  397         self.mock_server_group_list.assert_called_once_with(request)
  398 
  399     @test.create_mocks({api.nova: ['server_group_create']})
  400     def test_server_group_create(self):
  401         req_data = json.dumps({
  402             'name': 'server_group', 'policies': ['affinity']})
  403 
  404         self.mock_server_group_create.return_value = mock.Mock(**{
  405             'id': '123',
  406             'to_dict.return_value': {'id': '123',
  407                                      'name': 'server_group',
  408                                      'policies': ['affinity']}
  409         })
  410 
  411         server_group_data = {'name': 'server_group',
  412                              'policies': ['affinity']}
  413         request = self.mock_rest_request(body=req_data)
  414         response = nova.ServerGroups().post(request)
  415 
  416         self.assertStatusCode(response, 201)
  417         self.assertEqual('/api/nova/servergroups/123', response['location'])
  418 
  419         self.mock_server_group_create.assert_called_once_with(
  420             request, **server_group_data)
  421 
  422     @test.create_mocks({api.nova: ['server_group_delete']})
  423     def test_server_group_delete(self):
  424         request = self.mock_rest_request()
  425         self.mock_server_group_delete.return_value = None
  426         nova.ServerGroup().delete(request, "1")
  427         self.mock_server_group_delete.assert_called_once_with(request, "1")
  428 
  429     @test.create_mocks({api.nova: ['server_group_get']})
  430     def test_server_group_get_single(self):
  431         request = self.mock_rest_request()
  432         servergroup = self.server_groups.first()
  433         self.mock_server_group_get.return_value = servergroup
  434 
  435         response = nova.ServerGroup().get(request, "1")
  436 
  437         self.assertStatusCode(response, 200)
  438         self.assertEqual(servergroup.to_dict(), response.json)
  439         self.mock_server_group_get.assert_called_once_with(request, "1")
  440 
  441     #
  442     # Server Metadata
  443     #
  444     @test.create_mocks({api.nova: ['server_get']})
  445     def test_server_get_metadata(self):
  446         request = self.mock_rest_request()
  447         meta = {'foo': 'bar'}
  448         ret_val_server = self.mock_server_get.return_value
  449         ret_val_server.to_dict.return_value.get.return_value = meta
  450 
  451         response = nova.ServerMetadata().get(request, "1")
  452         self.assertStatusCode(response, 200)
  453         self.mock_server_get.assert_called_once_with(request, "1")
  454 
  455     @test.create_mocks({api.nova: ['server_metadata_delete',
  456                                    'server_metadata_update']})
  457     def test_server_edit_metadata(self):
  458         request = self.mock_rest_request(
  459             body='{"updated": {"a": "1", "b": "2"}, "removed": ["c", "d"]}'
  460         )
  461         self.mock_server_metadata_update.return_value = None
  462         self.mock_server_metadata_delete.return_value = None
  463 
  464         response = nova.ServerMetadata().patch(request, '1')
  465         self.assertStatusCode(response, 204)
  466         self.assertEqual(b'', response.content)
  467         self.mock_server_metadata_update.assert_called_once_with(
  468             request, '1', {'a': '1', 'b': '2'}
  469         )
  470         self.mock_server_metadata_delete.assert_called_once_with(
  471             request, '1', ['c', 'd']
  472         )
  473 
  474     #
  475     # Extensions
  476     #
  477     @test.create_mocks({api.nova: ['list_extensions']})
  478     @mock.patch.object(settings,
  479                        'OPENSTACK_NOVA_EXTENSIONS_BLACKLIST', ['baz'])
  480     def _test_extension_list(self):
  481         request = self.mock_rest_request()
  482         self.mock_list_extensions.return_value = [
  483             mock.Mock(**{'to_dict.return_value': {'name': 'foo'}}),
  484             mock.Mock(**{'to_dict.return_value': {'name': 'bar'}}),
  485             mock.Mock(**{'to_dict.return_value': {'name': 'baz'}}),
  486         ]
  487         response = nova.Extensions().get(request)
  488         self.assertStatusCode(response, 200)
  489         self.assertEqual({"items": [{"name": "foo"}, {"name": "bar"}]},
  490                          response.json)
  491         self.mock_list_extensions.assert_called_once_with(request)
  492 
  493     #
  494     # Flavors
  495     #
  496 
  497     @test.create_mocks({api.nova: ['flavor_get', 'flavor_access_list']})
  498     def test_flavor_get_single_with_access_list(self):
  499         request = self.mock_rest_request(GET={'get_access_list': 'tRuE'})
  500         self.mock_flavor_get.return_value.to_dict.return_value = {'name': '1'}
  501         self.mock_flavor_get.return_value.is_public = False
  502 
  503         self.mock_flavor_access_list.return_value = [
  504             mock.Mock(**{'tenant_id': '11'}),
  505             mock.Mock(**{'tenant_id': '22'}),
  506         ]
  507 
  508         response = nova.Flavor().get(request, "1")
  509 
  510         self.assertStatusCode(response, 200)
  511         self.assertEqual(to_json(response.content.decode('utf-8')),
  512                          to_json('{"access-list": ["11", "22"], "name": "1"}'))
  513 
  514         self.mock_flavor_get.assert_called_once_with(request, "1",
  515                                                      get_extras=False)
  516         self.mock_flavor_access_list.assert_called_once_with(request, "1")
  517 
  518     def test_get_extras_no(self):
  519         self._test_flavor_get_single(get_extras=False)
  520 
  521     def test_get_extras_yes(self):
  522         self._test_flavor_get_single(get_extras=True)
  523 
  524     def test_get_extras_default(self):
  525         self._test_flavor_get_single(get_extras=None)
  526 
  527     @test.create_mocks({api.nova: ['flavor_get']})
  528     def _test_flavor_get_single(self, get_extras):
  529         if get_extras:
  530             request = self.mock_rest_request(GET={'get_extras': 'tRuE'})
  531         elif get_extras is None:
  532             request = self.mock_rest_request()
  533             get_extras = False
  534         else:
  535             request = self.mock_rest_request(GET={'get_extras': 'fAlsE'})
  536         self.mock_flavor_get.return_value.to_dict.return_value = {'name': '1'}
  537 
  538         response = nova.Flavor().get(request, "1")
  539         self.assertStatusCode(response, 200)
  540         if get_extras:
  541             self.assertEqual(response.json, {"extras": {}, "name": "1"})
  542         else:
  543             self.assertEqual({"name": "1"}, response.json)
  544         self.mock_flavor_get.assert_called_once_with(request, "1",
  545                                                      get_extras=get_extras)
  546 
  547     @test.create_mocks({api.nova: ['flavor_get']})
  548     def test_flavor_get_single_with_swap_set_to_empty(self):
  549         request = self.mock_rest_request()
  550         self.mock_flavor_get.return_value\
  551             .to_dict.return_value = {'name': '1', 'swap': ''}
  552 
  553         response = nova.Flavor().get(request, "1")
  554 
  555         self.assertStatusCode(response, 200)
  556         self.assertEqual(to_json(response.content.decode('utf-8')),
  557                          to_json('{"name": "1", "swap": 0}'))
  558         self.mock_flavor_get.assert_called_once_with(request, '1',
  559                                                      get_extras=False)
  560 
  561     @test.create_mocks({api.nova: ['flavor_delete']})
  562     def test_flavor_delete(self):
  563         self.mock_flavor_delete.return_value = None
  564         request = self.mock_rest_request()
  565         nova.Flavor().delete(request, "1")
  566         self.mock_flavor_delete.assert_called_once_with(request, "1")
  567 
  568     @test.create_mocks({api.nova: ['flavor_create']})
  569     def test_flavor_create(self):
  570         flavor_req_data = '{"name": "flavor", ' \
  571                           '"ram": 12, ' \
  572                           '"vcpus": 1, ' \
  573                           '"disk": 2, ' \
  574                           '"OS-FLV-EXT-DATA:ephemeral": 3, ' \
  575                           '"swap": 4, ' \
  576                           '"id": "123"' \
  577                           '}'
  578 
  579         self.mock_flavor_create.return_value = mock.Mock(**{
  580             'id': '123',
  581             'to_dict.return_value': {'id': '123', 'name': 'flavor'}
  582         })
  583 
  584         flavor_data = {'name': 'flavor',
  585                        'memory': 12,
  586                        'vcpu': 1,
  587                        'disk': 2,
  588                        'ephemeral': 3,
  589                        'swap': 4,
  590                        'flavorid': '123',
  591                        'is_public': True}
  592 
  593         request = self.mock_rest_request(body=flavor_req_data)
  594         response = nova.Flavors().post(request)
  595 
  596         self.assertStatusCode(response, 201)
  597         self.assertEqual('/api/nova/flavors/123', response['location'])
  598 
  599         self.mock_flavor_create.assert_called_once_with(request, **flavor_data)
  600 
  601     @test.create_mocks({api.nova: ['flavor_create',
  602                                    'add_tenant_to_flavor']})
  603     def test_flavor_create_with_access_list(self):
  604         flavor_req_data = '{"name": "flavor", ' \
  605                           '"ram": 12, ' \
  606                           '"vcpus": 1, ' \
  607                           '"disk": 2, ' \
  608                           '"OS-FLV-EXT-DATA:ephemeral": 3, ' \
  609                           '"swap": 4, ' \
  610                           '"id": "123", ' \
  611                           '"flavor_access": [{"id":"1", "name":"test"}]' \
  612                           '}'
  613 
  614         self.mock_flavor_create.return_value = mock.Mock(**{
  615             'id': '1234',
  616             'to_dict.return_value': {'id': '1234', 'name': 'flavor'}
  617         })
  618         # A list of FlavorAccess object is returned but it is actually unused.
  619         self.mock_add_tenant_to_flavor.return_value = [
  620             mock.sentinel.flavor_access1,
  621         ]
  622 
  623         flavor_data = {'name': 'flavor',
  624                        'memory': 12,
  625                        'vcpu': 1,
  626                        'disk': 2,
  627                        'ephemeral': 3,
  628                        'swap': 4,
  629                        'flavorid': '123',
  630                        'is_public': False}
  631 
  632         request = self.mock_rest_request(body=flavor_req_data)
  633         response = nova.Flavors().post(request)
  634 
  635         self.assertStatusCode(response, 201)
  636         self.assertEqual('/api/nova/flavors/1234', response['location'])
  637 
  638         self.mock_flavor_create.assert_called_once_with(request, **flavor_data)
  639         self.mock_add_tenant_to_flavor.assert_called_once_with(
  640             request, '1234', '1')
  641 
  642     @test.create_mocks({api.nova: ['flavor_create',
  643                                    'flavor_delete',
  644                                    'flavor_get_extras']})
  645     def test_flavor_update(self):
  646         flavor_req_data = '{"name": "flavor", ' \
  647                           '"ram": 12, ' \
  648                           '"vcpus": 1, ' \
  649                           '"disk": 2, ' \
  650                           '"OS-FLV-EXT-DATA:ephemeral": 3, ' \
  651                           '"swap": 4' \
  652                           '}'
  653 
  654         self.mock_flavor_get_extras.return_value = {}
  655         self.mock_flavor_create.return_value = mock.Mock(**{
  656             'id': '123',
  657             'to_dict.return_value': {'id': '123', 'name': 'flavor'}
  658         })
  659         self.mock_flavor_delete.return_value = None
  660 
  661         flavor_data = {'name': 'flavor',
  662                        'memory': 12,
  663                        'vcpu': 1,
  664                        'disk': 2,
  665                        'ephemeral': 3,
  666                        'swap': 4,
  667                        'flavorid': '123',
  668                        'is_public': True}
  669 
  670         request = self.mock_rest_request(body=flavor_req_data)
  671         response = nova.Flavor().patch(request, '123')
  672 
  673         self.assertStatusCode(response, 204)
  674 
  675         self.mock_flavor_get_extras.assert_called_once_with(
  676             request, '123', raw=True)
  677         self.mock_flavor_delete.assert_called_once_with(request, '123')
  678         self.mock_flavor_create.assert_called_once_with(request, **flavor_data)
  679 
  680     @test.create_mocks({api.nova: ['flavor_create', 'flavor_delete',
  681                                    'flavor_extra_set', 'flavor_get_extras']})
  682     def test_flavor_update_with_extras(self):
  683         flavor_req_data = '{"name": "flavor", ' \
  684                           '"ram": 12, ' \
  685                           '"vcpus": 1, ' \
  686                           '"disk": 2, ' \
  687                           '"OS-FLV-EXT-DATA:ephemeral": 3, ' \
  688                           '"swap": 4' \
  689                           '}'
  690 
  691         extra_dict = mock.Mock()
  692 
  693         self.mock_flavor_get_extras.return_value = extra_dict
  694         self.mock_flavor_create.return_value = mock.Mock(**{
  695             'id': '1234',
  696             'to_dict.return_value': {'id': '1234', 'name': 'flavor'}
  697         })
  698         self.mock_flavor_delete.return_value = None
  699         self.mock_flavor_extra_set.return_value = None
  700 
  701         flavor_data = {'name': 'flavor',
  702                        'memory': 12,
  703                        'vcpu': 1,
  704                        'disk': 2,
  705                        'ephemeral': 3,
  706                        'swap': 4,
  707                        'flavorid': '123',
  708                        'is_public': True}
  709 
  710         request = self.mock_rest_request(body=flavor_req_data)
  711         response = nova.Flavor().patch(request, '123')
  712 
  713         self.assertStatusCode(response, 204)
  714 
  715         self.mock_flavor_delete.assert_called_once_with(request, '123')
  716         self.mock_flavor_create.assert_called_once_with(request, **flavor_data)
  717         self.mock_flavor_get_extras.assert_called_once_with(request, '123',
  718                                                             raw=True)
  719         self.mock_flavor_extra_set.assert_called_once_with(request, '1234',
  720                                                            extra_dict)
  721 
  722     @test.create_mocks({api.nova: ['flavor_create',
  723                                    'flavor_delete',
  724                                    'flavor_get_extras',
  725                                    'add_tenant_to_flavor']})
  726     def test_flavor_update_with_access_list(self):
  727         flavor_req_data = '{"name": "flavor", ' \
  728                           '"ram": 12, ' \
  729                           '"vcpus": 1, ' \
  730                           '"disk": 2, ' \
  731                           '"OS-FLV-EXT-DATA:ephemeral": 3, ' \
  732                           '"swap": 4, ' \
  733                           '"flavor_access": [{"id":"1", "name":"test"}]' \
  734                           '}'
  735 
  736         self.mock_flavor_get_extras.return_value = {}
  737         self.mock_flavor_create.return_value = mock.Mock(**{
  738             'id': '1234',
  739             'to_dict.return_value': {'id': '1234', 'name': 'flavor'}
  740         })
  741         self.mock_flavor_delete.return_value = None
  742         # A list of FlavorAccess object is returned but it is actually unused.
  743         self.mock_add_tenant_to_flavor.return_value = [
  744             mock.sentinel.flavor_access1,
  745         ]
  746 
  747         flavor_data = {'name': 'flavor',
  748                        'memory': 12,
  749                        'vcpu': 1,
  750                        'disk': 2,
  751                        'ephemeral': 3,
  752                        'swap': 4,
  753                        'flavorid': '123',
  754                        'is_public': False}
  755 
  756         request = self.mock_rest_request(body=flavor_req_data)
  757         response = nova.Flavor().patch(request, '123')
  758 
  759         self.assertStatusCode(response, 204)
  760 
  761         self.mock_flavor_get_extras.assert_called_once_with(
  762             request, '123', raw=True)
  763         self.mock_flavor_delete.assert_called_once_with(request, '123')
  764         self.mock_flavor_create.assert_called_once_with(request, **flavor_data)
  765         self.mock_add_tenant_to_flavor.assert_called_once_with(
  766             request, '1234', '1')
  767 
  768     @test.create_mocks({api.nova: ['flavor_list']})
  769     def _test_flavor_list_public(self, is_public=None):
  770         if is_public:
  771             request = self.mock_rest_request(GET={'is_public': 'tRuE'})
  772         elif is_public is None:
  773             request = self.mock_rest_request(GET={})
  774         else:
  775             request = self.mock_rest_request(GET={'is_public': 'fAlsE'})
  776         self.mock_flavor_list.return_value = [
  777             FakeFlavor("1"), FakeFlavor("2")
  778         ]
  779         response = nova.Flavors().get(request)
  780         self.assertStatusCode(response, 200)
  781         self.assertEqual({"items": [{"id": "1"}, {"id": "2"}]},
  782                          response.json)
  783         self.mock_flavor_list.assert_called_once_with(request,
  784                                                       is_public=is_public,
  785                                                       get_extras=False)
  786 
  787     def test_flavor_list_private(self):
  788         self._test_flavor_list_public(is_public=False)
  789 
  790     def test_flavor_list_public(self):
  791         self._test_flavor_list_public(is_public=True)
  792 
  793     def test_flavor_list_public_none(self):
  794         self._test_flavor_list_public(is_public=None)
  795 
  796     @test.create_mocks({api.nova: ['flavor_list']})
  797     def _test_flavor_list_extras(self, get_extras=None):
  798         if get_extras:
  799             request = self.mock_rest_request(GET={'get_extras': 'tRuE'})
  800         elif get_extras is None:
  801             request = self.mock_rest_request(GET={})
  802             get_extras = False
  803         else:
  804             request = self.mock_rest_request(GET={'get_extras': 'fAlsE'})
  805 
  806         self.mock_flavor_list.return_value = [
  807             FakeFlavor("1"), FakeFlavor("2")
  808         ]
  809         response = nova.Flavors().get(request)
  810         self.assertStatusCode(response, 200)
  811         if get_extras:
  812             self.assertEqual({"items": [{"extras": {}, "id": "1"},
  813                                         {"extras": {}, "id": "2"}]},
  814                              response.json)
  815         else:
  816             self.assertEqual({"items": [{"id": "1"}, {"id": "2"}]},
  817                              response.json)
  818         self.mock_flavor_list.assert_called_once_with(request, is_public=None,
  819                                                       get_extras=get_extras)
  820 
  821     def test_flavor_list_extras_no(self):
  822         self._test_flavor_list_extras(get_extras=False)
  823 
  824     def test_flavor_list_extras_yes(self):
  825         self._test_flavor_list_extras(get_extras=True)
  826 
  827     def test_flavor_list_extras_absent(self):
  828         self._test_flavor_list_extras(get_extras=None)
  829 
  830     @test.create_mocks({api.nova: ['flavor_get_extras']})
  831     def test_flavor_get_extra_specs(self):
  832         request = self.mock_rest_request()
  833         self.mock_flavor_get_extras.return_value.to_dict.return_value = \
  834             {'foo': '1'}
  835 
  836         response = nova.FlavorExtraSpecs().get(request, "1")
  837         self.assertStatusCode(response, 200)
  838         self.mock_flavor_get_extras.assert_called_once_with(request, "1",
  839                                                             raw=True)
  840 
  841     @test.create_mocks({api.nova: ['flavor_extra_delete',
  842                                    'flavor_extra_set']})
  843     def test_flavor_edit_extra_specs(self):
  844         request = self.mock_rest_request(
  845             body='{"updated": {"a": "1", "b": "2"}, "removed": ["c", "d"]}'
  846         )
  847         self.mock_flavor_extra_delete.return_value = None
  848         self.mock_flavor_extra_set.return_value = {'a': '1', 'b': '2'}
  849 
  850         response = nova.FlavorExtraSpecs().patch(request, '1')
  851         self.assertStatusCode(response, 204)
  852         self.assertEqual(b'', response.content)
  853         self.mock_flavor_extra_set.assert_called_once_with(
  854             request, '1', {'a': '1', 'b': '2'}
  855         )
  856         self.mock_flavor_extra_delete.assert_called_once_with(
  857             request, '1', ['c', 'd']
  858         )
  859 
  860     @test.create_mocks({api.nova: ['aggregate_get']})
  861     def test_aggregate_get_extra_specs(self):
  862         request = self.mock_rest_request()
  863         self.mock_aggregate_get.return_value.metadata = {'a': '1', 'b': '2'}
  864 
  865         response = nova.AggregateExtraSpecs().get(request, "1")
  866         self.assertStatusCode(response, 200)
  867         self.assertEqual({"a": "1", "b": "2"}, response.json)
  868         self.mock_aggregate_get.assert_called_once_with(request, "1")
  869 
  870     @test.create_mocks({api.nova: ['aggregate_set_metadata']})
  871     def test_aggregate_edit_extra_specs(self):
  872         self.mock_aggregate_set_metadata.return_value = self.aggregates.first()
  873         request = self.mock_rest_request(
  874             body='{"updated": {"a": "1", "b": "2"}, "removed": ["c", "d"]}'
  875         )
  876 
  877         response = nova.AggregateExtraSpecs().patch(request, '1')
  878         self.assertStatusCode(response, 204)
  879         self.assertEqual(b'', response.content)
  880         self.mock_aggregate_set_metadata.assert_called_once_with(
  881             request, '1', {'a': '1', 'b': '2', 'c': None, 'd': None}
  882         )
  883 
  884     #
  885     # Services
  886     #
  887 
  888     @test.create_mocks({api.base: ['is_service_enabled'],
  889                         api.nova: ['service_list',
  890                                    'extension_supported']})
  891     def test_services_get(self):
  892         request = self.mock_rest_request(GET={})
  893         self.mock_service_list.return_value = [
  894             mock.Mock(**{'to_dict.return_value': {'id': '1'}}),
  895             mock.Mock(**{'to_dict.return_value': {'id': '2'}})
  896         ]
  897         self.mock_is_service_enabled.return_value = True
  898         self.mock_extension_supported.return_value = True
  899 
  900         response = nova.Services().get(request)
  901 
  902         self.assertStatusCode(response, 200)
  903         self.assertEqual('{"items": [{"id": "1"}, {"id": "2"}]}',
  904                          response.content.decode('utf-8'))
  905         self.mock_service_list.assert_called_once_with(request)
  906         self.mock_is_service_enabled.assert_called_once_with(request,
  907                                                              'compute')
  908         self.mock_extension_supported.assert_called_once_with(
  909             'Services', request)
  910 
  911     @mock.patch.object(api.base, 'is_service_enabled')
  912     def test_services_get_disabled(self, mock_is_service_enabled):
  913         request = self.mock_rest_request(GET={})
  914         mock_is_service_enabled.return_value = False
  915 
  916         response = nova.Services().get(request)
  917 
  918         self.assertStatusCode(response, 501)
  919         mock_is_service_enabled.assert_called_once_with(request, 'compute')
  920 
  921     @test.create_mocks({api.base: ['is_service_enabled'],
  922                         quotas: ['get_disabled_quotas'],
  923                         api.nova: ['default_quota_get']})
  924     def test_quota_sets_defaults_get(self):
  925         filters = {'user': {'tenant_id': 'tenant'}}
  926         request = self.mock_rest_request(**{'GET': dict(filters)})
  927 
  928         self.mock_is_service_enabled.return_value = True
  929         self.mock_get_disabled_quotas.return_value = ['floating_ips']
  930         self.mock_default_quota_get.return_value = [
  931             Quota('metadata_items', 100),
  932             Quota('floating_ips', 1),
  933             Quota('q2', 101)
  934         ]
  935 
  936         response = nova.DefaultQuotaSets().get(request)
  937         self.assertStatusCode(response, 200)
  938         self.assertEqual(response.json,
  939                          {"items": [
  940                              {"limit": 100,
  941                               "display_name": "Metadata Items",
  942                               "name": "metadata_items"},
  943                              {"limit": 101,
  944                               "display_name": "Q2",
  945                               "name": "q2"}
  946                          ]})
  947 
  948         self.mock_is_service_enabled.assert_called_once_with(request,
  949                                                              'compute')
  950         self.mock_get_disabled_quotas.assert_called_once_with(request)
  951         self.mock_default_quota_get.assert_called_once_with(
  952             request, request.user.tenant_id)
  953 
  954     @test.create_mocks({api.base: ['is_service_enabled']})
  955     def test_quota_sets_defaults_get_when_service_is_disabled(self):
  956         filters = {'user': {'tenant_id': 'tenant'}}
  957         request = self.mock_rest_request(**{'GET': dict(filters)})
  958         self.mock_is_service_enabled.return_value = False
  959 
  960         response = nova.DefaultQuotaSets().get(request)
  961 
  962         self.assertStatusCode(response, 501)
  963         self.assertEqual(response.content.decode('utf-8'),
  964                          '"Service Nova is disabled."')
  965         self.mock_is_service_enabled.assert_called_once_with(request,
  966                                                              'compute')
  967 
  968     @test.create_mocks({api.base: ['is_service_enabled'],
  969                         quotas: ['get_disabled_quotas'],
  970                         api.nova: ['default_quota_update']})
  971     def test_quota_sets_defaults_patch(self):
  972         request = self.mock_rest_request(body='''
  973             {"key_pairs": "15", "metadata_items": "5000",
  974             "cores": "10", "instances": "20", "floating_ips": 10,
  975             "injected_file_content_bytes": "15",
  976             "injected_file_path_bytes": "5000",
  977             "injected_files": "5", "ram": "10", "gigabytes": "5"}
  978         ''')
  979 
  980         self.mock_is_service_enabled.return_value = True
  981         self.mock_get_disabled_quotas.return_value = ['floating_ips']
  982         self.mock_default_quota_update.return_value = None
  983 
  984         response = nova.DefaultQuotaSets().patch(request)
  985 
  986         self.assertStatusCode(response, 204)
  987         self.assertEqual(response.content.decode('utf-8'), '')
  988 
  989         self.mock_is_service_enabled.assert_called_once_with(request,
  990                                                              'compute')
  991         self.mock_get_disabled_quotas.assert_called_once_with(request)
  992         self.mock_default_quota_update.assert_called_once_with(
  993             request, key_pairs='15',
  994             metadata_items='5000', cores='10',
  995             instances='20', injected_file_content_bytes='15',
  996             injected_file_path_bytes='5000',
  997             injected_files='5', ram='10')
  998 
  999     @test.create_mocks({api.base: ['is_service_enabled']})
 1000     def test_quota_sets_defaults_patch_when_service_is_disabled(self):
 1001         request = self.mock_rest_request(body='''
 1002             {"key_pairs": "15", "metadata_items": "5000",
 1003             "cores": "10", "instances": "20", "floating_ips": 10,
 1004             "injected_file_content_bytes": "15",
 1005             "injected_file_path_bytes": "5000",
 1006             "injected_files": "5", "ram": "10", "gigabytes": "5"}
 1007         ''')
 1008 
 1009         self.mock_is_service_enabled.return_value = False
 1010 
 1011         response = nova.DefaultQuotaSets().patch(request)
 1012 
 1013         self.assertStatusCode(response, 501)
 1014         self.assertEqual(response.content.decode('utf-8'),
 1015                          '"Service Nova is disabled."')
 1016 
 1017         self.mock_is_service_enabled.assert_called_once_with(request,
 1018                                                              'compute')
 1019 
 1020     @test.create_mocks({quotas: ['get_disabled_quotas']})
 1021     def test_editable_quotas_get(self):
 1022         disabled_quotas = {'floating_ips', 'fixed_ips',
 1023                            'security_groups', 'security_group_rules'}
 1024         editable_quotas = {'cores', 'volumes', 'network', 'fixed_ips'}
 1025         self.mock_get_disabled_quotas.return_value = disabled_quotas
 1026         request = self.mock_rest_request()
 1027 
 1028         with mock.patch.object(quotas, 'QUOTA_FIELDS', editable_quotas):
 1029             response = nova.EditableQuotaSets().get(request)
 1030 
 1031         self.assertStatusCode(response, 200)
 1032         # NOTE(amotoki): assertItemsCollectionEqual cannot be used below
 1033         # since the item list is generated from a set and the order of items
 1034         # is unpredictable.
 1035         self.assertEqual(set(response.json['items']),
 1036                          {'cores', 'volumes', 'network'})
 1037         self.mock_get_disabled_quotas.assert_called_once_with(request)
 1038 
 1039     @test.create_mocks({api.base: ['is_service_enabled'],
 1040                         quotas: ['get_disabled_quotas'],
 1041                         api.nova: ['tenant_quota_update']})
 1042     def test_quota_sets_patch(self):
 1043         quota_data = dict(cores='15', instances='5',
 1044                           ram='50000', metadata_items='150',
 1045                           injected_files='5',
 1046                           injected_file_content_bytes='10240',
 1047                           floating_ips='50', fixed_ips='5',
 1048                           security_groups='10',
 1049                           security_group_rules='100')
 1050 
 1051         request = self.mock_rest_request(body='''
 1052             {"cores": "15", "ram": "50000", "instances": "5",
 1053              "metadata_items": "150", "injected_files": "5",
 1054              "injected_file_content_bytes": "10240", "floating_ips": "50",
 1055              "fixed_ips": "5", "security_groups": "10" ,
 1056              "security_group_rules": "100", "volumes": "10"}
 1057         ''')
 1058 
 1059         self.mock_get_disabled_quotas.return_value = set()
 1060         self.mock_is_service_enabled.return_value = True
 1061         self.mock_tenant_quota_update.return_value = None
 1062 
 1063         with mock.patch.object(quotas, 'NOVA_QUOTA_FIELDS',
 1064                                {n for n in quota_data}):
 1065             response = nova.QuotaSets().patch(request, 'spam123')
 1066 
 1067         self.assertStatusCode(response, 204)
 1068         self.assertEqual(response.content.decode('utf-8'), '')
 1069         self.mock_is_service_enabled.assert_called_once_with(request,
 1070                                                              'compute')
 1071         self.mock_get_disabled_quotas.assert_called_once_with(request)
 1072         self.mock_tenant_quota_update.assert_called_once_with(
 1073             request, 'spam123', **quota_data)
 1074 
 1075     @test.create_mocks({api.nova: ['tenant_quota_update'],
 1076                         api.base: ['is_service_enabled'],
 1077                         quotas: ['get_disabled_quotas']})
 1078     def test_quota_sets_patch_when_service_is_disabled(self):
 1079         quota_data = dict(cores='15', instances='5',
 1080                           ram='50000', metadata_items='150',
 1081                           injected_files='5',
 1082                           injected_file_content_bytes='10240',
 1083                           floating_ips='50', fixed_ips='5',
 1084                           security_groups='10',
 1085                           security_group_rules='100')
 1086 
 1087         request = self.mock_rest_request(body='''
 1088             {"cores": "15", "ram": "50000", "instances": "5",
 1089              "metadata_items": "150", "injected_files": "5",
 1090              "injected_file_content_bytes": "10240", "floating_ips": "50",
 1091              "fixed_ips": "5", "security_groups": "10" ,
 1092              "security_group_rules": "100", "volumes": "10"}
 1093         ''')
 1094 
 1095         self.mock_get_disabled_quotas.return_value = {}
 1096         self.mock_is_service_enabled.return_value = False
 1097         self.mock_tenant_quota_update.return_value = None
 1098 
 1099         with mock.patch.object(quotas, 'NOVA_QUOTA_FIELDS',
 1100                                {n for n in quota_data}):
 1101             response = nova.QuotaSets().patch(request, 'spam123')
 1102 
 1103         self.assertStatusCode(response, 501)
 1104         self.assertEqual(response.content.decode('utf-8'),
 1105                          '"Service Nova is disabled."')
 1106         self.mock_get_disabled_quotas.assert_called_once_with(request)
 1107         self.mock_is_service_enabled.assert_called_once_with(request,
 1108                                                              'compute')
 1109         self.mock_tenant_quota_update.assert_not_called()
 1110 
 1111     @test.create_mocks({api.nova: ['is_feature_available']})
 1112     def test_version_get(self):
 1113         request = self.mock_rest_request()
 1114         self.mock_is_feature_available.return_value = True
 1115 
 1116         response = nova.Features().get(request, 'fake')
 1117         self.assertStatusCode(response, 200)
 1118         self.assertEqual(response.content.decode('utf-8'), 'true')
 1119         self.mock_is_feature_available.assert_called_once_with(request,
 1120                                                                ('fake',))