8697a93d18
Because v1_1 is deprecated. Closes-bug: #1435201 Change-Id: I12a8c961d90bc79cc44b7c7f4e1a4bdbfa55f6a2
881 lines
36 KiB
Python
881 lines
36 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import json
|
|
|
|
from django.core.urlresolvers import reverse
|
|
from django import http
|
|
from mox import IsA # noqa
|
|
|
|
from openstack_dashboard import api
|
|
from openstack_dashboard.test import helpers as test
|
|
|
|
from novaclient.v2 import flavors
|
|
|
|
from openstack_dashboard.dashboards.admin.flavors import constants
|
|
from openstack_dashboard.dashboards.admin.flavors import workflows
|
|
|
|
|
|
class FlavorsViewTests(test.BaseAdminViewTests):
|
|
@test.create_stubs({api.nova: ('flavor_list',),
|
|
flavors.Flavor: ('get_keys',), })
|
|
def test_index(self):
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
flavors.Flavor.get_keys().MultipleTimes().AndReturn({})
|
|
self.mox.ReplayAll()
|
|
|
|
res = self.client.get(reverse(constants.FLAVORS_INDEX_URL))
|
|
self.assertTemplateUsed(res, constants.FLAVORS_TEMPLATE_NAME)
|
|
self.assertItemsEqual(res.context['table'].data, self.flavors.list())
|
|
|
|
|
|
class BaseFlavorWorkflowTests(test.BaseAdminViewTests):
|
|
def _flavor_create_params(self, flavor, id=None):
|
|
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
|
|
flavor_info = {"name": flavor.name,
|
|
"vcpu": flavor.vcpus,
|
|
"memory": flavor.ram,
|
|
"disk": flavor.disk,
|
|
"swap": flavor.swap,
|
|
"ephemeral": eph,
|
|
"is_public": flavor.is_public}
|
|
if id:
|
|
flavor_info["flavorid"] = id
|
|
return flavor_info
|
|
|
|
def _get_workflow_fields(self, flavor, id=None, access=None):
|
|
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
|
|
flavor_info = {"name": flavor.name,
|
|
"vcpus": flavor.vcpus,
|
|
"memory_mb": flavor.ram,
|
|
"disk_gb": flavor.disk,
|
|
"swap_mb": flavor.swap,
|
|
"eph_gb": eph}
|
|
if access:
|
|
access_field_name = 'update_flavor_access_role_member'
|
|
flavor_info[access_field_name] = [p.id for p in access]
|
|
if id:
|
|
flavor_info['flavor_id'] = id
|
|
return flavor_info
|
|
|
|
def _get_workflow_data(self, flavor, id=None, access=None):
|
|
flavor_info = self._get_workflow_fields(flavor, access=access,
|
|
id=id)
|
|
return flavor_info
|
|
|
|
|
|
class CreateFlavorWorkflowTests(BaseFlavorWorkflowTests):
|
|
@test.create_stubs({api.keystone: ('tenant_list',), })
|
|
def test_workflow_get(self):
|
|
projects = self.tenants.list()
|
|
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([projects,
|
|
False])
|
|
self.mox.ReplayAll()
|
|
|
|
url = reverse(constants.FLAVORS_CREATE_URL)
|
|
res = self.client.get(url)
|
|
self.assertTemplateUsed(res, constants.FLAVORS_CREATE_VIEW_TEMPLATE)
|
|
workflow = res.context['workflow']
|
|
expected_name = workflows.CreateFlavor.name
|
|
self.assertEqual(res.context['workflow'].name, expected_name)
|
|
self.assertQuerysetEqual(
|
|
workflow.steps,
|
|
['<CreateFlavorInfo: createflavorinfoaction>',
|
|
'<UpdateFlavorAccess: update_flavor_access>'])
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_list',
|
|
'flavor_create',)})
|
|
def test_create_flavor_without_projects_post(self):
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
|
|
# init
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([projects,
|
|
False])
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn([])
|
|
|
|
# handle
|
|
params = self._flavor_create_params(flavor, id='auto')
|
|
api.nova.flavor_create(IsA(http.HttpRequest), **params) \
|
|
.AndReturn(flavor)
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
workflow_data = self._get_workflow_data(flavor)
|
|
|
|
url = reverse(constants.FLAVORS_CREATE_URL)
|
|
res = self.client.post(url, workflow_data)
|
|
|
|
self.assertNoFormErrors(res)
|
|
self.assertRedirectsNoFollow(res, reverse(constants.FLAVORS_INDEX_URL))
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_list',
|
|
'flavor_create',
|
|
'add_tenant_to_flavor',)})
|
|
def test_create_flavor_with_projects_post(self):
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
|
|
# init
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([projects,
|
|
False])
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn([])
|
|
|
|
# handle
|
|
params = self._flavor_create_params(flavor, id='auto')
|
|
params['is_public'] = False
|
|
api.nova.flavor_create(IsA(http.HttpRequest), **params) \
|
|
.AndReturn(flavor)
|
|
for project in projects:
|
|
api.nova.add_tenant_to_flavor(IsA(http.HttpRequest),
|
|
flavor.id, project.id)
|
|
self.mox.ReplayAll()
|
|
|
|
workflow_data = self._get_workflow_data(flavor, access=projects)
|
|
|
|
url = reverse(constants.FLAVORS_CREATE_URL)
|
|
res = self.client.post(url, workflow_data)
|
|
|
|
self.assertNoFormErrors(res)
|
|
self.assertRedirectsNoFollow(res, reverse(constants.FLAVORS_INDEX_URL))
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_list',)})
|
|
def test_create_existing_flavor_name_error(self):
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
|
|
# init
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([projects,
|
|
False])
|
|
|
|
# handle
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
self.mox.ReplayAll()
|
|
|
|
workflow_data = self._get_workflow_data(flavor)
|
|
|
|
url = reverse(constants.FLAVORS_CREATE_URL)
|
|
res = self.client.post(url, workflow_data)
|
|
|
|
self.assertFormErrors(res)
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_list',)})
|
|
def test_create_existing_flavor_id_error(self):
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
|
|
# init
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([projects,
|
|
False])
|
|
|
|
# handle
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
self.mox.ReplayAll()
|
|
|
|
workflow_data = self._get_workflow_data(flavor)
|
|
# Name is okay.
|
|
workflow_data['name'] = 'newflavorname'
|
|
# Flavor id already exists.
|
|
workflow_data['flavor_id'] = flavor.id
|
|
|
|
url = reverse(constants.FLAVORS_CREATE_URL)
|
|
res = self.client.post(url, workflow_data)
|
|
|
|
self.assertFormErrors(res)
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_list',
|
|
'flavor_create',
|
|
'add_tenant_to_flavor',)})
|
|
def test_create_flavor_project_update_error(self):
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
|
|
# init
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([projects,
|
|
False])
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn([])
|
|
|
|
# handle
|
|
params = self._flavor_create_params(flavor, id='auto')
|
|
params['is_public'] = False
|
|
api.nova.flavor_create(IsA(http.HttpRequest), **params) \
|
|
.AndReturn(flavor)
|
|
for project in projects:
|
|
expect = api.nova.add_tenant_to_flavor(IsA(http.HttpRequest),
|
|
flavor.id, project.id)
|
|
if project == projects[0]:
|
|
expect.AndRaise(self.exceptions.nova)
|
|
self.mox.ReplayAll()
|
|
|
|
workflow_data = self._get_workflow_data(flavor, access=projects)
|
|
|
|
url = reverse(constants.FLAVORS_CREATE_URL)
|
|
res = self.client.post(url, workflow_data)
|
|
|
|
self.assertNoFormErrors(res)
|
|
self.assertMessageCount(error=1, warning=0)
|
|
self.assertRedirectsNoFollow(res, reverse(constants.FLAVORS_INDEX_URL))
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_list',)})
|
|
def test_create_flavor_missing_field_error(self):
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
|
|
# init
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([projects,
|
|
False])
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn([])
|
|
self.mox.ReplayAll()
|
|
|
|
workflow_data = self._get_workflow_data(flavor)
|
|
workflow_data["name"] = ""
|
|
|
|
url = reverse(constants.FLAVORS_CREATE_URL)
|
|
res = self.client.post(url, workflow_data)
|
|
|
|
self.assertFormErrors(res)
|
|
self.assertContains(res, "field is required")
|
|
|
|
|
|
class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests):
|
|
@test.create_stubs({api.nova: ('flavor_get',
|
|
'flavor_access_list',),
|
|
api.keystone: ('tenant_list',)})
|
|
def test_update_flavor_get(self):
|
|
flavor = self.flavors.list()[2]
|
|
flavor_access = self.flavor_access.list()
|
|
projects = self.tenants.list()
|
|
|
|
# GET/init, set up expected behavior
|
|
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id) \
|
|
.MultipleTimes().AndReturn(flavor)
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([projects,
|
|
False])
|
|
api.nova.flavor_access_list(IsA(http.HttpRequest), flavor.id) \
|
|
.AndReturn(flavor_access)
|
|
|
|
# Put all mocks created by mox into replay mode
|
|
self.mox.ReplayAll()
|
|
|
|
url = reverse(constants.FLAVORS_UPDATE_URL, args=[flavor.id])
|
|
res = self.client.get(url)
|
|
|
|
self.assertTemplateUsed(res, constants.FLAVORS_UPDATE_VIEW_TEMPLATE)
|
|
|
|
workflow = res.context['workflow']
|
|
expected_name = workflows.UpdateFlavor.name
|
|
self.assertEqual(res.context['workflow'].name, expected_name)
|
|
|
|
self.assertQuerysetEqual(
|
|
workflow.steps,
|
|
['<UpdateFlavorInfo: update_info>',
|
|
'<UpdateFlavorAccess: update_flavor_access>'])
|
|
|
|
step = workflow.get_step("update_info")
|
|
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
|
|
self.assertEqual(step.action.initial['name'], flavor.name)
|
|
self.assertEqual(step.action.initial['vcpus'], flavor.vcpus)
|
|
self.assertEqual(step.action.initial['memory_mb'], flavor.ram)
|
|
self.assertEqual(step.action.initial['disk_gb'], flavor.disk)
|
|
self.assertEqual(step.action.initial['swap_mb'], flavor.swap)
|
|
self.assertEqual(step.action.initial['eph_gb'], eph)
|
|
|
|
step = workflow.get_step("update_flavor_access")
|
|
field_name = step.get_member_field_name('member')
|
|
self.assertEqual(step.action.fields[field_name].initial,
|
|
[fa.tenant_id for fa in flavor_access])
|
|
|
|
@test.create_stubs({api.nova: ('flavor_get',), })
|
|
def test_update_flavor_get_flavor_error(self):
|
|
flavor = self.flavors.first()
|
|
|
|
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id) \
|
|
.AndRaise(self.exceptions.nova)
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
url = reverse(constants.FLAVORS_UPDATE_URL, args=[flavor.id])
|
|
res = self.client.get(url)
|
|
|
|
self.assertRedirectsNoFollow(res, reverse(constants.FLAVORS_INDEX_URL))
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_get',
|
|
'flavor_get_extras',
|
|
'flavor_list',
|
|
'flavor_delete',
|
|
'flavor_create')})
|
|
def test_update_flavor_without_extra_specs(self):
|
|
# The first element has no extra specs
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
|
|
extra_specs = getattr(flavor, 'extra_specs')
|
|
new_flavor = flavors.Flavor(flavors.FlavorManager(None),
|
|
{'id':
|
|
"cccccccc-cccc-cccc-cccc-cccccccccccc",
|
|
'name': flavor.name,
|
|
'vcpus': flavor.vcpus + 1,
|
|
'disk': flavor.disk,
|
|
'ram': flavor.ram,
|
|
'swap': 0,
|
|
'OS-FLV-EXT-DATA:ephemeral': eph,
|
|
'extra_specs': extra_specs})
|
|
|
|
# GET/init, set up expected behavior
|
|
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id) \
|
|
.MultipleTimes().AndReturn(flavor)
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
|
.MultipleTimes().AndReturn([projects, False])
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
|
|
# POST/init
|
|
api.nova.flavor_get_extras(IsA(http.HttpRequest),
|
|
flavor.id, raw=True) \
|
|
.AndReturn(extra_specs)
|
|
api.nova.flavor_delete(IsA(http.HttpRequest), flavor.id)
|
|
api.nova.flavor_create(IsA(http.HttpRequest),
|
|
new_flavor.name,
|
|
new_flavor.ram,
|
|
new_flavor.vcpus,
|
|
new_flavor.disk,
|
|
swap=new_flavor.swap,
|
|
ephemeral=eph,
|
|
is_public=True).AndReturn(new_flavor)
|
|
|
|
# Put mocks in replay mode
|
|
self.mox.ReplayAll()
|
|
|
|
# run get test
|
|
url = reverse(constants.FLAVORS_UPDATE_URL, args=[flavor.id])
|
|
resp = self.client.get(url)
|
|
self.assertEqual(resp.status_code, 200)
|
|
self.assertTemplateUsed(resp, constants.FLAVORS_UPDATE_VIEW_TEMPLATE)
|
|
|
|
# run post test
|
|
workflow_data = {'flavor_id': flavor.id,
|
|
'name': new_flavor.name,
|
|
'vcpus': new_flavor.vcpus,
|
|
'memory_mb': new_flavor.ram,
|
|
'disk_gb': new_flavor.disk,
|
|
'swap_mb': new_flavor.swap,
|
|
'eph_gb': eph,
|
|
'is_public': True}
|
|
resp = self.client.post(url, workflow_data)
|
|
self.assertNoFormErrors(resp)
|
|
self.assertMessageCount(success=1)
|
|
self.assertRedirectsNoFollow(resp,
|
|
reverse(constants.FLAVORS_INDEX_URL))
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_get',
|
|
'flavor_get_extras',
|
|
'flavor_list',
|
|
'flavor_delete',
|
|
'flavor_create',
|
|
'flavor_extra_set')})
|
|
def test_update_flavor_with_extra_specs(self):
|
|
# The second element has extra specs
|
|
flavor = self.flavors.list()[1]
|
|
projects = self.tenants.list()
|
|
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
|
|
extra_specs = getattr(flavor, 'extra_specs')
|
|
new_flavor = flavors.Flavor(flavors.FlavorManager(None),
|
|
{'id':
|
|
"cccccccc-cccc-cccc-cccc-cccccccccccc",
|
|
'name': flavor.name,
|
|
'vcpus': flavor.vcpus + 1,
|
|
'disk': flavor.disk,
|
|
'ram': flavor.ram,
|
|
'swap': flavor.swap,
|
|
'OS-FLV-EXT-DATA:ephemeral': eph,
|
|
'extra_specs': extra_specs})
|
|
|
|
# GET/init, set up expected behavior
|
|
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id) \
|
|
.MultipleTimes().AndReturn(flavor)
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
|
.MultipleTimes().AndReturn([projects, False])
|
|
|
|
# POST/init
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
api.nova.flavor_get_extras(IsA(http.HttpRequest),
|
|
flavor.id, raw=True) \
|
|
.AndReturn(extra_specs)
|
|
api.nova.flavor_delete(IsA(http.HttpRequest), flavor.id)
|
|
api.nova.flavor_create(IsA(http.HttpRequest),
|
|
new_flavor.name,
|
|
new_flavor.ram,
|
|
new_flavor.vcpus,
|
|
new_flavor.disk,
|
|
swap=new_flavor.swap,
|
|
ephemeral=eph,
|
|
is_public=True).AndReturn(new_flavor)
|
|
api.nova.flavor_extra_set(IsA(http.HttpRequest),
|
|
new_flavor.id, extra_specs)
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
# run get test
|
|
url = reverse(constants.FLAVORS_UPDATE_URL, args=[flavor.id])
|
|
resp = self.client.get(url)
|
|
self.assertEqual(resp.status_code, 200)
|
|
self.assertTemplateUsed(resp, constants.FLAVORS_UPDATE_VIEW_TEMPLATE)
|
|
|
|
# run post test
|
|
workflow_data = {'flavor_id': flavor.id,
|
|
'name': new_flavor.name,
|
|
'vcpus': new_flavor.vcpus,
|
|
'memory_mb': new_flavor.ram,
|
|
'disk_gb': new_flavor.disk,
|
|
'swap_mb': new_flavor.swap,
|
|
'eph_gb': eph,
|
|
'is_public': True}
|
|
resp = self.client.post(url, workflow_data)
|
|
self.assertNoFormErrors(resp)
|
|
self.assertMessageCount(success=1)
|
|
self.assertRedirectsNoFollow(resp,
|
|
reverse(constants.FLAVORS_INDEX_URL))
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_get',
|
|
'flavor_get_extras',
|
|
'flavor_list',
|
|
'flavor_delete',
|
|
'flavor_create')})
|
|
def test_update_flavor_update_flavor_error(self):
|
|
# The first element has no extra specs
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
|
|
extra_specs = getattr(flavor, 'extra_specs')
|
|
new_flavor = flavors.Flavor(flavors.FlavorManager(None),
|
|
{'id':
|
|
"cccccccc-cccc-cccc-cccc-cccccccccccc",
|
|
'name': flavor.name,
|
|
'vcpus': flavor.vcpus + 1,
|
|
'disk': flavor.disk,
|
|
'ram': flavor.ram,
|
|
'swap': 0,
|
|
'OS-FLV-EXT-DATA:ephemeral': eph,
|
|
'extra_specs': extra_specs})
|
|
|
|
# GET/init, set up expected behavior
|
|
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id) \
|
|
.MultipleTimes().AndReturn(flavor)
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
|
.MultipleTimes().AndReturn([projects, False])
|
|
|
|
# POST
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
|
|
# POST/init
|
|
api.nova.flavor_get_extras(IsA(http.HttpRequest),
|
|
flavor.id, raw=True) \
|
|
.AndReturn(extra_specs)
|
|
api.nova.flavor_delete(IsA(http.HttpRequest), flavor.id)
|
|
api.nova.flavor_create(IsA(http.HttpRequest),
|
|
new_flavor.name,
|
|
new_flavor.ram,
|
|
new_flavor.vcpus,
|
|
new_flavor.disk,
|
|
swap=new_flavor.swap,
|
|
ephemeral=eph,
|
|
is_public=True)\
|
|
.AndRaise(self.exceptions.nova)
|
|
|
|
# Put mocks in replay mode
|
|
self.mox.ReplayAll()
|
|
|
|
# run get test
|
|
url = reverse(constants.FLAVORS_UPDATE_URL, args=[flavor.id])
|
|
resp = self.client.get(url)
|
|
self.assertEqual(resp.status_code, 200)
|
|
self.assertTemplateUsed(resp, constants.FLAVORS_UPDATE_VIEW_TEMPLATE)
|
|
|
|
# run post test
|
|
workflow_data = {'flavor_id': flavor.id,
|
|
'name': new_flavor.name,
|
|
'vcpus': new_flavor.vcpus,
|
|
'memory_mb': new_flavor.ram,
|
|
'disk_gb': new_flavor.disk,
|
|
'swap_mb': new_flavor.swap,
|
|
'eph_gb': eph,
|
|
'is_public': True}
|
|
resp = self.client.post(url, workflow_data)
|
|
self.assertNoFormErrors(resp)
|
|
self.assertMessageCount(error=1)
|
|
self.assertRedirectsNoFollow(resp,
|
|
reverse(constants.FLAVORS_INDEX_URL))
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_get',
|
|
'flavor_get_extras',
|
|
'flavor_list',
|
|
'flavor_delete',
|
|
'flavor_create',
|
|
'flavor_access_list',
|
|
'remove_tenant_from_flavor',
|
|
'add_tenant_to_flavor')})
|
|
def test_update_flavor_update_projects_error(self):
|
|
# The first element has no extra specs
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
flavor_projects = [self.tenants.first()]
|
|
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
|
|
extra_specs = getattr(flavor, 'extra_specs')
|
|
new_flavor = flavors.Flavor(flavors.FlavorManager(None),
|
|
{'id':
|
|
"cccccccc-cccc-cccc-cccc-cccccccccccc",
|
|
'name': flavor.name,
|
|
'vcpus': flavor.vcpus + 1,
|
|
'disk': flavor.disk,
|
|
'ram': flavor.ram,
|
|
'swap': 0,
|
|
'OS-FLV-EXT-DATA:ephemeral': eph,
|
|
'os-flavor-access:is_public': False,
|
|
'extra_specs': extra_specs})
|
|
|
|
# GET/init, set up expected behavior
|
|
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id) \
|
|
.MultipleTimes().AndReturn(flavor)
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
|
.MultipleTimes().AndReturn([projects, False])
|
|
|
|
# POST/init
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
api.nova.flavor_get_extras(IsA(http.HttpRequest),
|
|
flavor.id, raw=True) \
|
|
.AndReturn(extra_specs)
|
|
|
|
api.nova.flavor_delete(IsA(http.HttpRequest), flavor.id)
|
|
api.nova.flavor_create(IsA(http.HttpRequest),
|
|
new_flavor.name,
|
|
new_flavor.ram,
|
|
new_flavor.vcpus,
|
|
new_flavor.disk,
|
|
swap=new_flavor.swap,
|
|
ephemeral=eph,
|
|
is_public=new_flavor.is_public) \
|
|
.AndReturn(new_flavor)
|
|
|
|
new_flavor_projects = flavor_projects
|
|
for project in new_flavor_projects:
|
|
expect = api.nova.add_tenant_to_flavor(IsA(http.HttpRequest),
|
|
new_flavor.id, project.id)
|
|
if project == projects[0]:
|
|
expect.AndRaise(self.exceptions.nova)
|
|
|
|
# Put mocks in replay mode
|
|
self.mox.ReplayAll()
|
|
|
|
# run get test
|
|
url = reverse(constants.FLAVORS_UPDATE_URL, args=[flavor.id])
|
|
resp = self.client.get(url)
|
|
self.assertEqual(resp.status_code, 200)
|
|
self.assertTemplateUsed(resp, constants.FLAVORS_UPDATE_VIEW_TEMPLATE)
|
|
|
|
# run post test
|
|
data = self._get_workflow_data(new_flavor, access=flavor_projects)
|
|
data['flavor_id'] = flavor.id
|
|
resp = self.client.post(url, data)
|
|
self.assertNoFormErrors(resp)
|
|
self.assertMessageCount(error=1, warning=0)
|
|
self.assertRedirectsNoFollow(resp,
|
|
reverse(constants.FLAVORS_INDEX_URL))
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_get',
|
|
'flavor_list',)})
|
|
def test_update_flavor_set_invalid_name(self):
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
|
|
invalid_flavor_name = "m1.tiny()"
|
|
|
|
# init
|
|
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id) \
|
|
.MultipleTimes().AndReturn(flavor)
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
|
.MultipleTimes().AndReturn([projects, False])
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
# run get test
|
|
url = reverse(constants.FLAVORS_UPDATE_URL, args=[flavor.id])
|
|
resp = self.client.get(url)
|
|
self.assertEqual(resp.status_code, 200)
|
|
self.assertTemplateUsed(resp, constants.FLAVORS_UPDATE_VIEW_TEMPLATE)
|
|
|
|
# run post test
|
|
workflow_data = {'flavor_id': flavor.id,
|
|
'name': invalid_flavor_name,
|
|
'vcpus': flavor.vcpus + 1,
|
|
'memory_mb': flavor.ram,
|
|
'disk_gb': flavor.disk,
|
|
'swap_mb': flavor.swap,
|
|
'eph_gb': eph,
|
|
'is_public': True}
|
|
resp = self.client.post(url, workflow_data)
|
|
self.assertFormErrors(resp, 1, 'Name may only contain letters, '
|
|
'numbers, underscores, periods and hyphens.')
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_get',
|
|
'flavor_list',)})
|
|
def test_update_flavor_set_existing_name(self):
|
|
flavor_a = self.flavors.list()[0]
|
|
flavor_b = self.flavors.list()[1]
|
|
projects = self.tenants.list()
|
|
eph = getattr(flavor_a, 'OS-FLV-EXT-DATA:ephemeral')
|
|
extra_specs = getattr(flavor_a, 'extra_specs')
|
|
new_flavor = flavors.Flavor(flavors.FlavorManager(None),
|
|
{'id': flavor_a.id,
|
|
'name': flavor_b.name,
|
|
'vcpus': flavor_a.vcpus,
|
|
'disk': flavor_a.disk,
|
|
'ram': flavor_a.ram,
|
|
'swap': flavor_a.swap,
|
|
'OS-FLV-EXT-DATA:ephemeral': eph,
|
|
'extra_specs': extra_specs})
|
|
|
|
# GET
|
|
api.nova.flavor_get(IsA(http.HttpRequest), flavor_a.id) \
|
|
.MultipleTimes().AndReturn(flavor_a)
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
|
.MultipleTimes().AndReturn([projects, False])
|
|
|
|
# POST
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
self.mox.ReplayAll()
|
|
|
|
# get test
|
|
url = reverse(constants.FLAVORS_UPDATE_URL, args=[flavor_a.id])
|
|
resp = self.client.get(url)
|
|
self.assertEqual(resp.status_code, 200)
|
|
self.assertTemplateUsed(resp, constants.FLAVORS_UPDATE_VIEW_TEMPLATE)
|
|
|
|
# post test
|
|
data = {'flavor_id': new_flavor.id,
|
|
'name': new_flavor.name,
|
|
'vcpus': new_flavor.vcpus,
|
|
'memory_mb': new_flavor.ram,
|
|
'disk_gb': new_flavor.disk,
|
|
'swap_mb': new_flavor.swap,
|
|
'eph_gb': eph,
|
|
'is_public': True}
|
|
resp = self.client.post(url, data)
|
|
self.assertFormErrors(resp, 1, 'The name "m1.massive" '
|
|
'is already used by another flavor.')
|
|
|
|
@test.create_stubs({api.keystone: ('tenant_list',),
|
|
api.nova: ('flavor_get',
|
|
'flavor_list',)})
|
|
def generic_update_flavor_invalid_data_form_fails(self, override_data,
|
|
error_msg):
|
|
flavor = self.flavors.first()
|
|
projects = self.tenants.list()
|
|
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
|
|
|
|
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id) \
|
|
.MultipleTimes().AndReturn(flavor)
|
|
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
|
.MultipleTimes().AndReturn([projects, False])
|
|
api.nova.flavor_list(IsA(http.HttpRequest), None) \
|
|
.AndReturn(self.flavors.list())
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
# run get test
|
|
url = reverse(constants.FLAVORS_UPDATE_URL, args=[flavor.id])
|
|
resp = self.client.get(url)
|
|
self.assertEqual(resp.status_code, 200)
|
|
self.assertTemplateUsed(resp, constants.FLAVORS_UPDATE_VIEW_TEMPLATE)
|
|
|
|
# run post test
|
|
workflow_data = {'flavor_id': flavor.id,
|
|
'name': flavor.name,
|
|
'vcpus': flavor.vcpus,
|
|
'memory_mb': flavor.ram,
|
|
'disk_gb': flavor.disk,
|
|
'swap_mb': flavor.swap,
|
|
'eph_gb': eph,
|
|
'is_public': True}
|
|
workflow_data.update(override_data)
|
|
resp = self.client.post(url, workflow_data)
|
|
self.assertFormErrors(resp, 1, error_msg)
|
|
|
|
def test_update_flavor_invalid_vcpu_fails(self):
|
|
error = 'Ensure this value is greater than or equal to 1.'
|
|
data = {'vcpus': 0}
|
|
self.generic_update_flavor_invalid_data_form_fails(override_data=data,
|
|
error_msg=error)
|
|
|
|
def test_update_flavor_invalid_ram_fails(self):
|
|
error = 'Ensure this value is greater than or equal to 1.'
|
|
data = {'memory_mb': 0}
|
|
self.generic_update_flavor_invalid_data_form_fails(override_data=data,
|
|
error_msg=error)
|
|
|
|
def test_update_flavor_invalid_disk_gb_fails(self):
|
|
error = 'Ensure this value is greater than or equal to 0.'
|
|
data = {'disk_gb': -1}
|
|
self.generic_update_flavor_invalid_data_form_fails(override_data=data,
|
|
error_msg=error)
|
|
|
|
def test_update_flavor_invalid_swap_mb_fails(self):
|
|
error = 'Ensure this value is greater than or equal to 0.'
|
|
data = {'swap_mb': -1}
|
|
self.generic_update_flavor_invalid_data_form_fails(override_data=data,
|
|
error_msg=error)
|
|
|
|
def test_update_flavor_invalid_eph_gb_fails(self):
|
|
error = 'Ensure this value is greater than or equal to 0.'
|
|
data = {'eph_gb': -1}
|
|
self.generic_update_flavor_invalid_data_form_fails(override_data=data,
|
|
error_msg=error)
|
|
|
|
|
|
class FlavorUpdateMetadataViewTest(test.BaseAdminViewTests):
|
|
@test.create_stubs({api.nova: ('flavor_get_extras',),
|
|
api.glance: ('metadefs_namespace_list',
|
|
'metadefs_namespace_get')})
|
|
def test_flavor_metadata_get(self):
|
|
# <Flavor: m1.metadata>
|
|
flavor = self.flavors.list()[3]
|
|
|
|
namespaces = self.metadata_defs.list()
|
|
|
|
api.nova.flavor_get_extras(
|
|
IsA(http.HttpRequest),
|
|
flavor.id
|
|
).AndReturn([flavor.extra_specs])
|
|
api.glance.metadefs_namespace_list(
|
|
IsA(http.HttpRequest),
|
|
filters={
|
|
'resource_types': ['OS::Nova::Flavor']
|
|
}
|
|
).AndReturn((namespaces, False, False))
|
|
|
|
for namespace in namespaces:
|
|
api.glance.metadefs_namespace_get(
|
|
IsA(http.HttpRequest),
|
|
namespace.namespace,
|
|
'OS::Nova::Flavor'
|
|
).AndReturn(namespace)
|
|
|
|
self.mox.ReplayAll()
|
|
res = self.client.get(
|
|
reverse(
|
|
constants.FLAVORS_UPDATE_METADATA_URL,
|
|
kwargs={'id': flavor.id}
|
|
)
|
|
)
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
self.assertTemplateUsed(
|
|
res,
|
|
constants.FLAVORS_UPDATE_METADATA_TEMPLATE
|
|
)
|
|
self.assertTemplateUsed(
|
|
res,
|
|
constants.FLAVORS_UPDATE_METADATA_SUBTEMPLATE
|
|
)
|
|
self.assertContains(res, 'namespace_1')
|
|
self.assertContains(res, 'namespace_2')
|
|
self.assertContains(res, 'namespace_3')
|
|
self.assertContains(res, 'namespace_4')
|
|
|
|
@test.create_stubs({api.nova: ('flavor_get_extras',
|
|
'flavor_extra_set',
|
|
'flavor_extra_delete')})
|
|
def test_flavor_metadata_update(self):
|
|
# <Flavor: m1.metadata>
|
|
flavor = self.flavors.list()[3]
|
|
|
|
api.nova.flavor_get_extras(
|
|
IsA(http.HttpRequest),
|
|
flavor.id
|
|
).AndReturn([flavor.extra_specs])
|
|
api.nova.flavor_extra_set(
|
|
IsA(http.HttpRequest),
|
|
flavor.id,
|
|
{'key_mock': 'value_mock'}
|
|
).AndReturn(None)
|
|
api.nova.flavor_extra_delete(
|
|
IsA(http.HttpRequest),
|
|
flavor.id,
|
|
[]
|
|
).AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
metadata = [{'value': 'value_mock', 'key': 'key_mock'}]
|
|
formData = {'metadata': json.dumps(metadata)}
|
|
|
|
res = self.client.post(
|
|
reverse(
|
|
constants.FLAVORS_UPDATE_METADATA_URL,
|
|
kwargs={'id': flavor.id}
|
|
),
|
|
formData
|
|
)
|
|
|
|
self.assertEqual(res.status_code, 302)
|
|
self.assertNoFormErrors(res)
|
|
self.assertRedirectsNoFollow(res, reverse(constants.FLAVORS_INDEX_URL))
|
|
self.assertMessageCount(success=1)
|
|
|
|
@test.create_stubs({api.nova: ('flavor_get_extras',)})
|
|
def test_flavor_metadata_get_get_extras_fails(self):
|
|
# <Flavor: m1.metadata>
|
|
flavor = self.flavors.list()[3]
|
|
|
|
api.nova.flavor_get_extras(
|
|
IsA(http.HttpRequest),
|
|
flavor.id
|
|
).AndRaise(self.exceptions.nova)
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
res = self.client.get(
|
|
reverse(
|
|
constants.FLAVORS_UPDATE_METADATA_URL,
|
|
kwargs={'id': flavor.id}
|
|
)
|
|
)
|
|
|
|
self.assertEqual(res.status_code, 302)
|
|
self.assertRedirectsNoFollow(res, reverse(constants.FLAVORS_INDEX_URL))
|
|
self.assertMessageCount(error=1)
|