Fixing Nameless Volume Display
When a volume has no name, it now shows the ID instead. I also added a fixture data that represents such a volume being in the system. Fixes bug #1012380 You can also now use truncate=i on DataTable Columns in order to have the value truncated if it goes beyond i characters. On top of this I fixed/made-clearer a bunch of the tests relating to volumes and instances. Please do NOT use deepcopy() of fixture data in tests any more, instead just create a new fixture for the data you want. Change-Id: If2f92b5d04b04f08f5cacca03f614fce5ea38702
This commit is contained in:
parent
2d0315030e
commit
c17b06d08a
@ -25,6 +25,7 @@ from copy import deepcopy
|
||||
|
||||
from horizon import api
|
||||
from horizon import test
|
||||
|
||||
from .tabs import InstanceDetailTabs
|
||||
from .workflows import LaunchInstance
|
||||
|
||||
@ -41,218 +42,251 @@ class InstanceViewTests(test.TestCase):
|
||||
super(InstanceViewTests, self).tearDown()
|
||||
self.reset_times()
|
||||
|
||||
@test.create_stubs({api: ('server_list',
|
||||
'flavor_list',
|
||||
'server_delete',
|
||||
'volume_list',)})
|
||||
def test_terminate_instance(self):
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
self.mox.StubOutWithMock(api, 'server_delete')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.flavor_list(IgnoreArg()).AndReturn(self.flavors.list())
|
||||
api.server_delete(IsA(http.HttpRequest), server.id)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__terminate__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('server_list',
|
||||
'flavor_list',
|
||||
'server_delete',
|
||||
'volume_list',)})
|
||||
def test_terminate_instance_exception(self):
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
self.mox.StubOutWithMock(api, 'server_delete')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.flavor_list(IgnoreArg()).AndReturn(self.flavors.list())
|
||||
api.server_delete(IsA(http.HttpRequest), server.id) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__terminate__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('server_pause',
|
||||
'server_list',
|
||||
'volume_list',
|
||||
'flavor_list',)})
|
||||
def test_pause_instance(self):
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api, 'server_pause')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_pause(IsA(http.HttpRequest), server.id)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__pause__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('server_pause',
|
||||
'server_list',
|
||||
'volume_list',
|
||||
'flavor_list',)})
|
||||
def test_pause_instance_exception(self):
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'server_pause')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_pause(IsA(http.HttpRequest), server.id) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__pause__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('volume_list',
|
||||
'server_unpause',
|
||||
'server_list',
|
||||
'flavor_list',)})
|
||||
def test_unpause_instance(self):
|
||||
server = self.servers.first()
|
||||
server.status = "PAUSED"
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'server_unpause')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_unpause(IsA(http.HttpRequest), server.id)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__pause__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('volume_list',
|
||||
'server_unpause',
|
||||
'server_list',
|
||||
'flavor_list',)})
|
||||
def test_unpause_instance_exception(self):
|
||||
server = self.servers.first()
|
||||
server.status = "PAUSED"
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'server_unpause')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_unpause(IsA(http.HttpRequest), server.id) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__pause__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('volume_list',
|
||||
'server_reboot',
|
||||
'server_list',
|
||||
'flavor_list',)})
|
||||
def test_reboot_instance(self):
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api, 'server_reboot')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_reboot(IsA(http.HttpRequest), server.id)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__reboot__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('volume_list',
|
||||
'server_reboot',
|
||||
'server_list',
|
||||
'flavor_list',)})
|
||||
def test_reboot_instance_exception(self):
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api, 'server_reboot')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_reboot(IsA(http.HttpRequest), server.id) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__reboot__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('volume_list',
|
||||
'server_suspend',
|
||||
'server_list',
|
||||
'flavor_list',)})
|
||||
def test_suspend_instance(self):
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api, 'server_suspend')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_suspend(IsA(http.HttpRequest), unicode(server.id))
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__suspend__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('volume_list',
|
||||
'server_suspend',
|
||||
'server_list',
|
||||
'flavor_list',)})
|
||||
def test_suspend_instance_exception(self):
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api, 'server_suspend')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_suspend(IsA(http.HttpRequest),
|
||||
unicode(server.id)).AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__suspend__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('volume_list',
|
||||
'server_resume',
|
||||
'server_list',
|
||||
'flavor_list',)})
|
||||
def test_resume_instance(self):
|
||||
server = self.servers.first()
|
||||
server.status = "SUSPENDED"
|
||||
self.mox.StubOutWithMock(api, 'server_resume')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_resume(IsA(http.HttpRequest), unicode(server.id))
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__suspend__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('volume_list',
|
||||
'server_resume',
|
||||
'server_list',
|
||||
'flavor_list',)})
|
||||
def test_resume_instance_exception(self):
|
||||
server = self.servers.first()
|
||||
server.status = "SUSPENDED"
|
||||
self.mox.StubOutWithMock(api, 'server_resume')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.server_resume(IsA(http.HttpRequest),
|
||||
unicode(server.id)).AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'instances__suspend__%s' % server.id}
|
||||
res = self.client.post(INDEX_URL, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ("server_get", "volume_instance_list",
|
||||
"flavor_get", "server_security_groups")})
|
||||
@test.create_stubs({api: ("server_get",
|
||||
"volume_instance_list",
|
||||
"flavor_get",
|
||||
"server_security_groups")})
|
||||
def test_instance_details_volumes(self):
|
||||
server = self.servers.first()
|
||||
volumes = deepcopy(self.volumes.list())
|
||||
volumes[0].device = "/dev/hdk"
|
||||
second_vol = deepcopy(volumes[0])
|
||||
second_vol.id = 2
|
||||
second_vol.device = "/dev/hdb"
|
||||
volumes.append(second_vol)
|
||||
volumes = [self.volumes.list()[1]]
|
||||
|
||||
api.server_get(IsA(http.HttpRequest), server.id).AndReturn(server)
|
||||
api.volume_instance_list(IsA(http.HttpRequest),
|
||||
@ -267,15 +301,41 @@ class InstanceViewTests(test.TestCase):
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:detail',
|
||||
args=[server.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertItemsEqual(res.context['instance'].volumes, volumes)
|
||||
|
||||
@test.create_stubs({api: ("server_get",
|
||||
"volume_instance_list",
|
||||
"flavor_get",
|
||||
"server_security_groups")})
|
||||
def test_instance_details_volume_sorting(self):
|
||||
server = self.servers.first()
|
||||
volumes = self.volumes.list()[1:3]
|
||||
|
||||
api.server_get(IsA(http.HttpRequest), server.id).AndReturn(server)
|
||||
api.volume_instance_list(IsA(http.HttpRequest),
|
||||
server.id).AndReturn(volumes)
|
||||
api.flavor_get(IsA(http.HttpRequest),
|
||||
server.flavor['id']).AndReturn(self.flavors.first())
|
||||
api.server_security_groups(IsA(http.HttpRequest),
|
||||
server.id).AndReturn(self.security_groups.first())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:detail',
|
||||
args=[server.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertItemsEqual(res.context['instance'].volumes, volumes)
|
||||
# Test device ordering
|
||||
self.assertEquals(res.context['instance'].volumes[0].device,
|
||||
"/dev/hdb")
|
||||
"/dev/hda")
|
||||
self.assertEquals(res.context['instance'].volumes[1].device,
|
||||
"/dev/hdk")
|
||||
|
||||
@test.create_stubs({api: ("server_get", "volume_instance_list",
|
||||
"flavor_get", "server_security_groups")})
|
||||
@test.create_stubs({api: ("server_get",
|
||||
"volume_instance_list",
|
||||
"flavor_get",
|
||||
"server_security_groups",)})
|
||||
def test_instance_details_metadata(self):
|
||||
server = self.servers.first()
|
||||
|
||||
@ -294,26 +354,25 @@ class InstanceViewTests(test.TestCase):
|
||||
tg = InstanceDetailTabs(self.request, instance=server)
|
||||
qs = "?%s=%s" % (tg.param_name, tg.get_tab("overview").get_id())
|
||||
res = self.client.get(url + qs)
|
||||
# Key name
|
||||
|
||||
self.assertContains(res, "<dd>keyName</dd>", 1)
|
||||
# Meta data
|
||||
self.assertContains(res, "<dt>someMetaLabel</dt>", 1)
|
||||
self.assertContains(res, "<dd>someMetaData</dd>", 1)
|
||||
# Test escaping of html characters in names
|
||||
self.assertContains(res, "<dt>some<b>html</b>label</dt>",
|
||||
1)
|
||||
self.assertContains(res, "<dd><!--</dd>", 1)
|
||||
self.assertContains(res, "<dt>empty</dt>", 1)
|
||||
self.assertContains(res, "<dd><em>N/A</em></dd>", 1)
|
||||
|
||||
@test.create_stubs({api: ('server_console_output',)})
|
||||
def test_instance_log(self):
|
||||
server = self.servers.first()
|
||||
CONSOLE_OUTPUT = 'output'
|
||||
|
||||
self.mox.StubOutWithMock(api, 'server_console_output')
|
||||
api.server_console_output(IsA(http.HttpRequest),
|
||||
server.id, tail_length=None) \
|
||||
.AndReturn(CONSOLE_OUTPUT)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:console',
|
||||
@ -321,17 +380,19 @@ class InstanceViewTests(test.TestCase):
|
||||
tg = InstanceDetailTabs(self.request, instance=server)
|
||||
qs = "?%s=%s" % (tg.param_name, tg.get_tab("log").get_id())
|
||||
res = self.client.get(url + qs)
|
||||
|
||||
self.assertNoMessages()
|
||||
self.assertIsInstance(res, http.HttpResponse)
|
||||
self.assertContains(res, CONSOLE_OUTPUT)
|
||||
|
||||
@test.create_stubs({api: ('server_console_output',)})
|
||||
def test_instance_log_exception(self):
|
||||
server = self.servers.first()
|
||||
|
||||
self.mox.StubOutWithMock(api, 'server_console_output')
|
||||
api.server_console_output(IsA(http.HttpRequest),
|
||||
server.id, tail_length=None) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:console',
|
||||
@ -339,6 +400,7 @@ class InstanceViewTests(test.TestCase):
|
||||
tg = InstanceDetailTabs(self.request, instance=server)
|
||||
qs = "?%s=%s" % (tg.param_name, tg.get_tab("log").get_id())
|
||||
res = self.client.get(url + qs)
|
||||
|
||||
self.assertContains(res, "Unable to get log for")
|
||||
|
||||
def test_instance_vnc(self):
|
||||
@ -360,33 +422,36 @@ class InstanceViewTests(test.TestCase):
|
||||
redirect = CONSOLE_OUTPUT + '&title=%s(1)' % server.name
|
||||
self.assertRedirectsNoFollow(res, redirect)
|
||||
|
||||
@test.create_stubs({api: ('server_vnc_console',)})
|
||||
def test_instance_vnc_exception(self):
|
||||
server = self.servers.first()
|
||||
|
||||
self.mox.StubOutWithMock(api, 'server_vnc_console')
|
||||
api.server_vnc_console(IsA(http.HttpRequest), server.id) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:vnc',
|
||||
args=[server.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('server_get',
|
||||
'snapshot_create',
|
||||
'snapshot_list_detailed',
|
||||
'image_list_detailed',
|
||||
'volume_snapshot_list',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'server_delete',
|
||||
'volume_list',)})
|
||||
def test_create_instance_snapshot(self):
|
||||
server = self.servers.first()
|
||||
snapshot_server = deepcopy(server)
|
||||
setattr(snapshot_server, 'OS-EXT-STS:task_state',
|
||||
"IMAGE_SNAPSHOT")
|
||||
self.mox.StubOutWithMock(api, 'server_get')
|
||||
self.mox.StubOutWithMock(api, 'snapshot_create')
|
||||
self.mox.StubOutWithMock(api, 'snapshot_list_detailed')
|
||||
self.mox.StubOutWithMock(api, 'image_list_detailed')
|
||||
self.mox.StubOutWithMock(api, 'volume_snapshot_list')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
self.mox.StubOutWithMock(api, 'server_delete')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
|
||||
api.server_get(IsA(http.HttpRequest), server.id).AndReturn(server)
|
||||
api.snapshot_create(IsA(http.HttpRequest),
|
||||
server.id,
|
||||
@ -397,10 +462,10 @@ class InstanceViewTests(test.TestCase):
|
||||
api.image_list_detailed(IsA(http.HttpRequest),
|
||||
marker=None).AndReturn([[], False])
|
||||
api.volume_snapshot_list(IsA(http.HttpRequest)).AndReturn([])
|
||||
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn([snapshot_server])
|
||||
api.flavor_list(IgnoreArg()).AndReturn(self.flavors.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'instance_id': server.id,
|
||||
@ -412,42 +477,48 @@ class InstanceViewTests(test.TestCase):
|
||||
redir_url = reverse('horizon:nova:images_and_snapshots:index')
|
||||
res = self.client.post(url, formData)
|
||||
self.assertRedirects(res, redir_url)
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertContains(res, '<td class="status_unknown sortable">'
|
||||
'Snapshotting</td>', 1)
|
||||
|
||||
@test.create_stubs({api: ('server_get',)})
|
||||
def test_instance_update_get(self):
|
||||
server = self.servers.first()
|
||||
|
||||
self.mox.StubOutWithMock(api, 'server_get')
|
||||
api.server_get(IsA(http.HttpRequest), server.id).AndReturn(server)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:update',
|
||||
args=[server.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res,
|
||||
'nova/instances_and_volumes/instances/update.html')
|
||||
|
||||
@test.create_stubs({api: ('server_get',)})
|
||||
def test_instance_update_get_server_get_exception(self):
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api, 'server_get')
|
||||
|
||||
api.server_get(IsA(http.HttpRequest), server.id) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:update',
|
||||
args=[server.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('server_get', 'server_update')})
|
||||
def test_instance_update_post(self):
|
||||
server = self.servers.first()
|
||||
|
||||
self.mox.StubOutWithMock(api, 'server_get')
|
||||
self.mox.StubOutWithMock(api, 'server_update')
|
||||
api.server_get(IsA(http.HttpRequest), server.id).AndReturn(server)
|
||||
api.server_update(IsA(http.HttpRequest), server.id, server.name)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'method': 'UpdateInstance',
|
||||
@ -457,16 +528,17 @@ class InstanceViewTests(test.TestCase):
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:update',
|
||||
args=[server.id])
|
||||
res = self.client.post(url, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api: ('server_get', 'server_update')})
|
||||
def test_instance_update_post_api_exception(self):
|
||||
server = self.servers.first()
|
||||
|
||||
self.mox.StubOutWithMock(api, 'server_get')
|
||||
self.mox.StubOutWithMock(api, 'server_update')
|
||||
api.server_get(IsA(http.HttpRequest), server.id).AndReturn(server)
|
||||
api.server_update(IsA(http.HttpRequest), server.id, server.name) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'method': 'UpdateInstance',
|
||||
@ -476,20 +548,19 @@ class InstanceViewTests(test.TestCase):
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:update',
|
||||
args=[server.id])
|
||||
res = self.client.post(url, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api.nova: ('tenant_quota_usages',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'security_group_list',
|
||||
'volume_snapshot_list',
|
||||
'volume_list',),
|
||||
api.glance: ('image_list_detailed',)})
|
||||
def test_launch_get(self):
|
||||
quota_usages = self.quota_usages.first()
|
||||
|
||||
self.mox.StubOutWithMock(api.glance, 'image_list_detailed')
|
||||
self.mox.StubOutWithMock(api.nova, 'tenant_quota_usages')
|
||||
# Two flavor_list calls, however, flavor_list is now memoized.
|
||||
self.mox.StubOutWithMock(api.nova, 'flavor_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'keypair_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'security_group_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_snapshot_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_list')
|
||||
|
||||
api.nova.volume_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.volumes.list())
|
||||
api.nova.volume_snapshot_list(IsA(http.HttpRequest)) \
|
||||
@ -510,20 +581,29 @@ class InstanceViewTests(test.TestCase):
|
||||
.AndReturn(self.keypairs.list())
|
||||
api.nova.security_group_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.security_groups.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:launch')
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res,
|
||||
'nova/instances_and_volumes/instances/launch.html')
|
||||
workflow = res.context['workflow']
|
||||
self.assertEqual(workflow.name, LaunchInstance.name)
|
||||
self.assertQuerysetEqual(workflow.steps,
|
||||
self.assertEqual(res.context['workflow'].name, LaunchInstance.name)
|
||||
self.assertQuerysetEqual(res.context['workflow'].steps,
|
||||
['<SetInstanceDetails: setinstancedetailsaction>',
|
||||
'<SetAccessControls: setaccesscontrolsaction>',
|
||||
'<VolumeOptions: volumeoptionsaction>',
|
||||
'<PostCreationStep: customizeaction>'])
|
||||
|
||||
@test.create_stubs({api.glance: ('image_list_detailed',),
|
||||
api.nova: ('flavor_list',
|
||||
'keypair_list',
|
||||
'security_group_list',
|
||||
'volume_list',
|
||||
'volume_snapshot_list',
|
||||
'tenant_quota_usages',
|
||||
'server_create',)})
|
||||
def test_launch_post(self):
|
||||
flavor = self.flavors.first()
|
||||
image = self.images.first()
|
||||
@ -536,15 +616,6 @@ class InstanceViewTests(test.TestCase):
|
||||
volume_choice = "%s:vol" % volume.id
|
||||
block_device_mapping = {device_name: u"%s::0" % volume_choice}
|
||||
|
||||
self.mox.StubOutWithMock(api.glance, 'image_list_detailed')
|
||||
self.mox.StubOutWithMock(api.nova, 'flavor_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'keypair_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'security_group_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_snapshot_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'tenant_quota_usages')
|
||||
self.mox.StubOutWithMock(api.nova, 'server_create')
|
||||
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.keypair_list(IsA(http.HttpRequest)) \
|
||||
@ -569,6 +640,7 @@ class InstanceViewTests(test.TestCase):
|
||||
[sec_group.name],
|
||||
block_device_mapping,
|
||||
instance_count=IsA(int))
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'flavor': flavor.id,
|
||||
@ -586,19 +658,19 @@ class InstanceViewTests(test.TestCase):
|
||||
'count': 1}
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:launch')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertRedirectsNoFollow(res,
|
||||
reverse('horizon:nova:instances_and_volumes:index'))
|
||||
|
||||
@test.create_stubs({api.glance: ('image_list_detailed',),
|
||||
api.nova: ('tenant_quota_usages',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'volume_list',
|
||||
'security_group_list',
|
||||
'volume_snapshot_list',)})
|
||||
def test_launch_flavorlist_error(self):
|
||||
self.mox.StubOutWithMock(api.glance, 'image_list_detailed')
|
||||
self.mox.StubOutWithMock(api.nova, 'tenant_quota_usages')
|
||||
self.mox.StubOutWithMock(api.nova, 'flavor_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'keypair_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'security_group_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_snapshot_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_list')
|
||||
|
||||
api.nova.volume_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.volumes.list())
|
||||
api.nova.volume_snapshot_list(IsA(http.HttpRequest)) \
|
||||
@ -619,13 +691,22 @@ class InstanceViewTests(test.TestCase):
|
||||
.AndReturn(self.keypairs.list())
|
||||
api.nova.security_group_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.security_groups.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:launch')
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res,
|
||||
'nova/instances_and_volumes/instances/launch.html')
|
||||
|
||||
@test.create_stubs({api.glance: ('image_list_detailed',),
|
||||
api.nova: ('flavor_list',
|
||||
'keypair_list',
|
||||
'security_group_list',
|
||||
'volume_list',
|
||||
'server_create',
|
||||
'volume_snapshot_list',)})
|
||||
def test_launch_form_keystone_exception(self):
|
||||
flavor = self.flavors.first()
|
||||
image = self.images.first()
|
||||
@ -634,14 +715,6 @@ class InstanceViewTests(test.TestCase):
|
||||
sec_group = self.security_groups.first()
|
||||
customization_script = 'userData'
|
||||
|
||||
self.mox.StubOutWithMock(api.glance, 'image_list_detailed')
|
||||
self.mox.StubOutWithMock(api.nova, 'flavor_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'keypair_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'security_group_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'server_create')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_snapshot_list')
|
||||
|
||||
api.nova.volume_snapshot_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.volumes.list())
|
||||
api.nova.flavor_list(IgnoreArg()).AndReturn(self.flavors.list())
|
||||
@ -665,6 +738,7 @@ class InstanceViewTests(test.TestCase):
|
||||
None,
|
||||
instance_count=IsA(int)) \
|
||||
.AndRaise(self.exceptions.keystone)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'flavor': flavor.id,
|
||||
@ -680,8 +754,16 @@ class InstanceViewTests(test.TestCase):
|
||||
'count': 1}
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:launch')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api.glance: ('image_list_detailed',),
|
||||
api.nova: ('flavor_list',
|
||||
'keypair_list',
|
||||
'security_group_list',
|
||||
'volume_list',
|
||||
'tenant_quota_usages',
|
||||
'volume_snapshot_list',)})
|
||||
def test_launch_form_instance_count_error(self):
|
||||
flavor = self.flavors.first()
|
||||
image = self.images.first()
|
||||
@ -693,14 +775,6 @@ class InstanceViewTests(test.TestCase):
|
||||
device_name = u'vda'
|
||||
volume_choice = "%s:vol" % volume.id
|
||||
|
||||
self.mox.StubOutWithMock(api.glance, 'image_list_detailed')
|
||||
self.mox.StubOutWithMock(api.nova, 'flavor_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'keypair_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'security_group_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_snapshot_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'tenant_quota_usages')
|
||||
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.keypair_list(IsA(http.HttpRequest)) \
|
||||
@ -721,6 +795,7 @@ class InstanceViewTests(test.TestCase):
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.quota_usages.first())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'flavor': flavor.id,
|
||||
@ -738,4 +813,5 @@ class InstanceViewTests(test.TestCase):
|
||||
'count': 0}
|
||||
url = reverse('horizon:nova:instances_and_volumes:instances:launch')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertContains(res, "greater than or equal to 1")
|
||||
|
@ -18,7 +18,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from copy import deepcopy
|
||||
from django import http
|
||||
from django.core.urlresolvers import reverse
|
||||
from mox import IsA
|
||||
@ -28,10 +27,8 @@ from horizon import test
|
||||
|
||||
|
||||
class InstancesAndVolumesViewTest(test.TestCase):
|
||||
@test.create_stubs({api: ('flavor_list', 'server_list', 'volume_list',)})
|
||||
def test_index(self):
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
@ -49,23 +46,12 @@ class InstancesAndVolumesViewTest(test.TestCase):
|
||||
self.assertItemsEqual(instances, self.servers.list())
|
||||
self.assertItemsEqual(volumes, self.volumes.list())
|
||||
|
||||
@test.create_stubs({api: ('flavor_list', 'server_list', 'volume_list',)})
|
||||
def test_attached_volume(self):
|
||||
volumes = deepcopy(self.volumes.list())
|
||||
attached_volume = deepcopy(self.volumes.list()[0])
|
||||
attached_volume.id = "2"
|
||||
attached_volume.display_name = "Volume2 name"
|
||||
attached_volume.size = "80"
|
||||
attached_volume.status = "in-use"
|
||||
attached_volume.attachments = [{"server_id": "1",
|
||||
"device": "/dev/hdn"}]
|
||||
volumes.append(attached_volume)
|
||||
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
self.mox.StubOutWithMock(api, 'flavor_list')
|
||||
api.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(volumes)
|
||||
api.volume_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.volumes.list()[1:3])
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -78,21 +64,20 @@ class InstancesAndVolumesViewTest(test.TestCase):
|
||||
resp_volumes = res.context['volumes_table'].data
|
||||
|
||||
self.assertItemsEqual(instances, self.servers.list())
|
||||
self.assertItemsEqual(resp_volumes, volumes)
|
||||
self.assertItemsEqual(resp_volumes, self.volumes.list()[1:3])
|
||||
|
||||
self.assertContains(res, ">Volume name<", 1, 200)
|
||||
self.assertContains(res, ">40GB<", 1, 200)
|
||||
self.assertContains(res, ">Available<", 1, 200)
|
||||
|
||||
self.assertContains(res, ">Volume2 name<", 1, 200)
|
||||
self.assertContains(res, ">80GB<", 1, 200)
|
||||
self.assertContains(res, ">In-Use<", 1, 200)
|
||||
self.assertContains(res, ">server_1<", 2, 200)
|
||||
self.assertContains(res, "on /dev/hdn", 1, 200)
|
||||
self.assertContains(res, ">My Volume<", 1, 200)
|
||||
self.assertContains(res, ">30GB<", 1, 200)
|
||||
self.assertContains(res, ">3b189ac8-9166-ac7f-90c9-16c8bf9e01ac<",
|
||||
1,
|
||||
200)
|
||||
self.assertContains(res, ">10GB<", 1, 200)
|
||||
self.assertContains(res, ">In-Use<", 2, 200)
|
||||
self.assertContains(res, "on /dev/hda", 1, 200)
|
||||
self.assertContains(res, "on /dev/hdk", 1, 200)
|
||||
|
||||
@test.create_stubs({api: ('server_list', 'volume_list',)})
|
||||
def test_index_server_list_exception(self):
|
||||
self.mox.StubOutWithMock(api, 'server_list')
|
||||
self.mox.StubOutWithMock(api, 'volume_list')
|
||||
api.server_list(IsA(http.HttpRequest)).AndRaise(self.exceptions.nova)
|
||||
api.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list())
|
||||
api.server_list(IsA(http.HttpRequest)).AndReturn(self.servers.list())
|
||||
|
@ -22,7 +22,6 @@
|
||||
"""
|
||||
Views for Instances and Volumes.
|
||||
"""
|
||||
import re
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
@ -73,16 +72,12 @@ class IndexView(tables.MultiTableView):
|
||||
instances = SortedDict([(inst.id, inst) for inst in
|
||||
self._get_instances()])
|
||||
for volume in volumes:
|
||||
# Truncate the description for proper display.
|
||||
if len(getattr(volume, 'display_description', '')) > 33:
|
||||
truncated_string = volume.display_description[:30].strip()
|
||||
# Remove non-word, and underscore characters, from the end
|
||||
# of the string before we add the ellepsis.
|
||||
truncated_string = re.sub(ur'[^\w\s]+$',
|
||||
'',
|
||||
truncated_string)
|
||||
# It is possible to create a volume with no name through the
|
||||
# EC2 API, use the ID in those cases.
|
||||
if not volume.display_name:
|
||||
volume.display_name = volume.id
|
||||
|
||||
volume.display_description = truncated_string + u'...'
|
||||
description = getattr(volume, 'display_description', '')
|
||||
|
||||
for att in volume.attachments:
|
||||
server_id = att.get('server_id', None)
|
||||
|
@ -135,7 +135,8 @@ class VolumesTableBase(tables.DataTable):
|
||||
name = tables.Column("display_name", verbose_name=_("Name"),
|
||||
link="%s:volumes:detail" % URL_PREFIX)
|
||||
description = tables.Column("display_description",
|
||||
verbose_name=_("Description"))
|
||||
verbose_name=_("Description"),
|
||||
truncate=40)
|
||||
size = tables.Column(get_size, verbose_name=_("Size"))
|
||||
status = tables.Column("status",
|
||||
filters=(title,),
|
||||
|
@ -18,7 +18,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from copy import deepcopy
|
||||
from django import http
|
||||
from django.core.urlresolvers import reverse
|
||||
from mox import IsA
|
||||
@ -28,14 +27,15 @@ from horizon import test
|
||||
|
||||
|
||||
class VolumeViewTests(test.TestCase):
|
||||
@test.create_stubs({api: ('volume_get',), api.nova: ('server_list',)})
|
||||
def test_edit_attachments(self):
|
||||
volume = self.volumes.first()
|
||||
servers = self.servers.list()
|
||||
self.mox.StubOutWithMock(api, 'volume_get')
|
||||
self.mox.StubOutWithMock(api.nova, 'server_list')
|
||||
|
||||
api.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
api.nova.server_list(IsA(http.HttpRequest)).AndReturn(servers)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:volumes:attach',
|
||||
@ -47,54 +47,42 @@ class VolumeViewTests(test.TestCase):
|
||||
2)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
@test.create_stubs({api: ('volume_get',),
|
||||
api.nova: ('server_get', 'server_list',)})
|
||||
def test_edit_attachments_attached_volume(self):
|
||||
server = self.servers.first()
|
||||
servers = deepcopy(self.servers)
|
||||
active_server = deepcopy(self.servers.first())
|
||||
active_server.status = 'ACTIVE'
|
||||
active_server.id = "3"
|
||||
servers.add(active_server)
|
||||
volumes = deepcopy(self.volumes)
|
||||
volume = deepcopy(self.volumes.first())
|
||||
volume.id = "2"
|
||||
volume.status = "in-use"
|
||||
volume.attachments = [{"id": "1", "server_id": server.id,
|
||||
"device": "/dev/hdn"}]
|
||||
volumes.add(volume)
|
||||
volume = self.volumes.list()[0]
|
||||
|
||||
self.mox.StubOutWithMock(api, 'volume_get')
|
||||
self.mox.StubOutWithMock(api.nova, 'server_list')
|
||||
self.mox.StubOutWithMock(api.nova, 'server_get')
|
||||
api.nova.server_get(IsA(http.HttpRequest), server.id).AndReturn(server)
|
||||
api.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
api.nova.server_list(IsA(http.HttpRequest)).AndReturn(servers.list())
|
||||
api.nova.server_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.servers.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:volumes:attach',
|
||||
args=[volume.id])
|
||||
res = self.client.get(url)
|
||||
# Asserting length of 1 instance (plus 'Select ..' item).
|
||||
# The other instance is already attached to this volume
|
||||
self.assertEqual(len(res.context['form'].fields['instance']._choices),
|
||||
2)
|
||||
|
||||
self.assertEqual(res.context['form'].\
|
||||
fields['instance']._choices[0][1],
|
||||
"Select an instance")
|
||||
# The instance choice should not be server_id = 3
|
||||
self.assertNotEqual(res.context['form'].\
|
||||
fields['instance']._choices[1][0],
|
||||
volume.attachments[0]['server_id'])
|
||||
self.assertEqual(len(res.context['form'].fields['instance'].choices),
|
||||
2)
|
||||
self.assertEqual(res.context['form'].fields['instance']._choices[1][0],
|
||||
server.id)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
@test.create_stubs({api.nova: ('volume_get', 'server_get',)})
|
||||
def test_detail_view(self):
|
||||
volume = self.volumes.first()
|
||||
server = self.servers.first()
|
||||
|
||||
volume.attachments = [{"server_id": server.id}]
|
||||
self.mox.StubOutWithMock(api.nova, 'volume_get')
|
||||
self.mox.StubOutWithMock(api.nova, 'server_get')
|
||||
|
||||
api.nova.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
|
||||
api.nova.server_get(IsA(http.HttpRequest), server.id).AndReturn(server)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:nova:instances_and_volumes:volumes:detail',
|
||||
@ -102,7 +90,8 @@ class VolumeViewTests(test.TestCase):
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertContains(res, "<dd>Volume name</dd>", 1, 200)
|
||||
self.assertContains(res, "<dd>1</dd>", 1, 200)
|
||||
self.assertContains(res, "<dd>41023e92-8008-4c8b-8059-" \
|
||||
"7f2293ff3775</dd>", 1, 200)
|
||||
self.assertContains(res, "<dd>Available</dd>", 1, 200)
|
||||
self.assertContains(res, "<dd>40 GB</dd>", 1, 200)
|
||||
self.assertContains(res, "<dd>04/01/12 at 10:30:00</dd>", 1, 200)
|
||||
|
@ -26,6 +26,7 @@ from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.core import urlresolvers
|
||||
from django.template.defaultfilters import truncatechars
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils import http
|
||||
from django.utils.datastructures import SortedDict
|
||||
@ -142,6 +143,14 @@ class Column(html.HTMLElement):
|
||||
|
||||
A dict of HTML attribute strings which should be added to this column.
|
||||
Example: ``attrs={"data-foo": "bar"}``.
|
||||
|
||||
.. attribute:: truncate
|
||||
|
||||
An integer for the maximum length of the string in this column. If the
|
||||
data in this column is larger than the supplied number, the data for
|
||||
this column will be truncated and an ellipsis will be appended to the
|
||||
truncated data.
|
||||
Defaults to ``None``.
|
||||
"""
|
||||
summation_methods = {
|
||||
"sum": sum,
|
||||
@ -172,31 +181,35 @@ class Column(html.HTMLElement):
|
||||
def __init__(self, transform, verbose_name=None, sortable=True,
|
||||
link=None, hidden=False, attrs=None, status=False,
|
||||
status_choices=None, display_choices=None, empty_value=None,
|
||||
filters=None, classes=None, summation=None, auto=None):
|
||||
filters=None, classes=None, summation=None, auto=None,
|
||||
truncate=None):
|
||||
self.classes = list(classes or getattr(self, "classes", []))
|
||||
super(Column, self).__init__()
|
||||
self.attrs.update(attrs or {})
|
||||
|
||||
self.auto = auto
|
||||
|
||||
if callable(transform):
|
||||
self.transform = transform
|
||||
self.name = transform.__name__
|
||||
else:
|
||||
self.transform = unicode(transform)
|
||||
self.name = self.transform
|
||||
self.sortable = sortable
|
||||
|
||||
# Empty string is a valid value for verbose_name
|
||||
if verbose_name is None:
|
||||
verbose_name = self.transform.title()
|
||||
else:
|
||||
verbose_name = verbose_name
|
||||
|
||||
self.auto = auto
|
||||
self.sortable = sortable
|
||||
self.verbose_name = verbose_name
|
||||
self.link = link
|
||||
self.hidden = hidden
|
||||
self.status = status
|
||||
self.empty_value = empty_value or '-'
|
||||
self.filters = filters or []
|
||||
self.truncate = truncate
|
||||
|
||||
if status_choices:
|
||||
self.status_choices = status_choices
|
||||
self.display_choices = display_choices
|
||||
@ -257,20 +270,29 @@ class Column(html.HTMLElement):
|
||||
method for this column.
|
||||
"""
|
||||
datum_id = self.table.get_object_id(datum)
|
||||
|
||||
if datum_id in self.table._data_cache[self]:
|
||||
return self.table._data_cache[self][datum_id]
|
||||
|
||||
data = self.get_raw_data(datum)
|
||||
display_value = None
|
||||
|
||||
if self.display_choices:
|
||||
display_value = [display for (value, display) in
|
||||
self.display_choices
|
||||
if value.lower() == (data or '').lower()]
|
||||
|
||||
if display_value:
|
||||
data = display_value[0]
|
||||
else:
|
||||
for filter_func in self.filters:
|
||||
data = filter_func(data)
|
||||
|
||||
if data and self.truncate:
|
||||
data = truncatechars(data, self.truncate)
|
||||
|
||||
self.table._data_cache[self][datum_id] = data
|
||||
|
||||
return self.table._data_cache[self][datum_id]
|
||||
|
||||
def get_link_url(self, datum):
|
||||
|
@ -56,6 +56,11 @@ TEST_DATA_4 = (
|
||||
FakeObject('2', 'object_2', 4, 'up'),
|
||||
)
|
||||
|
||||
TEST_DATA_5 = (
|
||||
FakeObject('1', 'object_1', 'A Value That is longer than 35 characters!',
|
||||
'down', 'optional_1'),
|
||||
)
|
||||
|
||||
|
||||
class MyLinkAction(tables.LinkAction):
|
||||
name = "login"
|
||||
@ -153,7 +158,8 @@ class MyTable(tables.DataTable):
|
||||
sortable=True,
|
||||
link='http://example.com/',
|
||||
attrs={'class': 'green blue'},
|
||||
summation="average")
|
||||
summation="average",
|
||||
truncate=35)
|
||||
status = tables.Column('status', link=get_link)
|
||||
optional = tables.Column('optional', empty_value='N/A')
|
||||
excluded = tables.Column('excluded')
|
||||
@ -379,6 +385,14 @@ class DataTableTests(test.TestCase):
|
||||
self.assertEqual(row.cells['status'].get_status_class(cell_status),
|
||||
'status_up')
|
||||
|
||||
def test_table_column_truncation(self):
|
||||
self.table = MyTable(self.request, TEST_DATA_5)
|
||||
row = self.table.get_rows()[0]
|
||||
|
||||
self.assertEqual(len(row.cells['value'].data), 35)
|
||||
self.assertEqual(row.cells['value'].data,
|
||||
u'A Value That is longer than 35 c...')
|
||||
|
||||
def test_table_rendering(self):
|
||||
self.table = MyTable(self.request, TEST_DATA)
|
||||
# Table actions
|
||||
|
@ -146,14 +146,38 @@ def data(TEST):
|
||||
|
||||
# Volumes
|
||||
volume = volumes.Volume(volumes.VolumeManager(None),
|
||||
dict(id="1",
|
||||
dict(id="41023e92-8008-4c8b-8059-7f2293ff3775",
|
||||
name='test_volume',
|
||||
status='available',
|
||||
size=40,
|
||||
display_name='Volume name',
|
||||
created_at='2012-04-01 10:30:00',
|
||||
attachments={}))
|
||||
attachments=[]))
|
||||
nameless_volume = volumes.Volume(volumes.VolumeManager(None),
|
||||
dict(id="3b189ac8-9166-ac7f-90c9-16c8bf9e01ac",
|
||||
name='',
|
||||
status='in-use',
|
||||
size=10,
|
||||
display_name='',
|
||||
display_description='',
|
||||
device="/dev/hda",
|
||||
created_at='2010-11-21 18:34:25',
|
||||
attachments=[{"id": "1", "server_id": '1',
|
||||
"device": "/dev/hda"}]))
|
||||
attached_volume = volumes.Volume(volumes.VolumeManager(None),
|
||||
dict(id="8cba67c1-2741-6c79-5ab6-9c2bf8c96ab0",
|
||||
name='my_volume',
|
||||
status='in-use',
|
||||
size=30,
|
||||
display_name='My Volume',
|
||||
display_description='',
|
||||
device="/dev/hdk",
|
||||
created_at='2011-05-01 11:54:33',
|
||||
attachments=[{"id": "2", "server_id": '1',
|
||||
"device": "/dev/hdk"}]))
|
||||
TEST.volumes.add(volume)
|
||||
TEST.volumes.add(nameless_volume)
|
||||
TEST.volumes.add(attached_volume)
|
||||
|
||||
# Flavors
|
||||
flavor_1 = flavors.Flavor(flavors.FlavorManager(None),
|
||||
|
Loading…
Reference in New Issue
Block a user