Merge lp:~soren/nova/image-tests into lp:~hudson-openstack/nova/trunk

Proposed by Soren Hansen
Status: Merged
Approved by: Devin Carlen
Approved revision: no longer in the source branch.
Merged at revision: 1385
Proposed branch: lp:~soren/nova/image-tests
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 256 lines (+169/-14)
3 files modified
nova/image/fake.py (+30/-11)
nova/tests/test_image.py (+132/-0)
nova/virt/libvirt/connection.py (+7/-3)
To merge this branch: bzr merge lp:~soren/nova/image-tests
Reviewer Review Type Date Requested Status
Devin Carlen (community) Approve
Josh Kearney (community) Approve
Review via email: mp+70570@code.launchpad.net

Commit message

Add a generic image service test and run it against the fake image service.

Description of the change

Add a generic image service test and run it against the fake image service.

I've removed a couple of things from the image dicts FakeImageService returns because they're not documented. If something needs them, we should update the documentation and make sure all the other drivers return them as well.

Right now, I just run these tests against the fake image service, but I want to run them against the other ones as well to make sure they all actually behave identically.

To post a comment you must log in.
lp:~soren/nova/image-tests updated
1381. By Matt Dietz

Fixes lp821144

Revert resize broken because an incorrect number of parameters and a bad call at the virt layer

Revision history for this message
Josh Kearney (jk0) wrote :

I'm game.

review: Approve
lp:~soren/nova/image-tests updated
1382. By Dan Prince

Add exception logging for instance IDs in the __public_instance_is_accessible smoke test function. This should help troubleshoot an intermittent failure.

1383. By Gabe Westmaas

Updates v1.1 servers/id/action requests to comply with the 1.1 spec

1384. By Justin Shepherd

Implemented @test.skip_unless and @test.skip_if functionality in nova/test.py.

Added nova/tests/test_skip_examples.py which contains example skip case usages.

Revision history for this message
Devin Carlen (devcamcar) wrote :

good stuff!

review: Approve
lp:~soren/nova/image-tests updated
1385. By Soren Hansen

Add a generic image service test and run it against the fake image service.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/image/fake.py'
2--- nova/image/fake.py 2011-07-08 09:35:01 +0000
3+++ nova/image/fake.py 2011-08-05 13:46:49 +0000
4@@ -45,9 +45,12 @@
5 'name': 'fakeimage123456',
6 'created_at': timestamp,
7 'updated_at': timestamp,
8+ 'deleted_at': None,
9+ 'deleted': False,
10 'status': 'active',
11- 'container_format': 'ami',
12- 'disk_format': 'raw',
13+ 'is_public': False,
14+# 'container_format': 'ami',
15+# 'disk_format': 'raw',
16 'properties': {'kernel_id': FLAGS.null_kernel,
17 'ramdisk_id': FLAGS.null_kernel,
18 'architecture': 'x86_64'}}
19@@ -56,9 +59,12 @@
20 'name': 'fakeimage123456',
21 'created_at': timestamp,
22 'updated_at': timestamp,
23+ 'deleted_at': None,
24+ 'deleted': False,
25 'status': 'active',
26- 'container_format': 'ami',
27- 'disk_format': 'raw',
28+ 'is_public': True,
29+# 'container_format': 'ami',
30+# 'disk_format': 'raw',
31 'properties': {'kernel_id': FLAGS.null_kernel,
32 'ramdisk_id': FLAGS.null_kernel}}
33
34@@ -66,9 +72,12 @@
35 'name': 'fakeimage123456',
36 'created_at': timestamp,
37 'updated_at': timestamp,
38+ 'deleted_at': None,
39+ 'deleted': False,
40 'status': 'active',
41- 'container_format': 'ami',
42- 'disk_format': 'raw',
43+ 'is_public': True,
44+# 'container_format': 'ami',
45+# 'disk_format': 'raw',
46 'properties': {'kernel_id': FLAGS.null_kernel,
47 'ramdisk_id': FLAGS.null_kernel}}
48
49@@ -76,9 +85,12 @@
50 'name': 'fakeimage123456',
51 'created_at': timestamp,
52 'updated_at': timestamp,
53+ 'deleted_at': None,
54+ 'deleted': False,
55 'status': 'active',
56- 'container_format': 'ami',
57- 'disk_format': 'raw',
58+ 'is_public': True,
59+# 'container_format': 'ami',
60+# 'disk_format': 'raw',
61 'properties': {'kernel_id': FLAGS.null_kernel,
62 'ramdisk_id': FLAGS.null_kernel}}
63
64@@ -86,9 +98,12 @@
65 'name': 'fakeimage123456',
66 'created_at': timestamp,
67 'updated_at': timestamp,
68+ 'deleted_at': None,
69+ 'deleted': False,
70 'status': 'active',
71- 'container_format': 'ami',
72- 'disk_format': 'raw',
73+ 'is_public': True,
74+# 'container_format': 'ami',
75+# 'disk_format': 'raw',
76 'properties': {'kernel_id': FLAGS.null_kernel,
77 'ramdisk_id': FLAGS.null_kernel}}
78
79@@ -101,7 +116,11 @@
80
81 def index(self, context, filters=None, marker=None, limit=None):
82 """Returns list of images."""
83- return copy.deepcopy(self.images.values())
84+ retval = []
85+ for img in self.images.values():
86+ retval += [dict([(k, v) for k, v in img.iteritems()
87+ if k in ['id', 'name']])]
88+ return retval
89
90 def detail(self, context, filters=None, marker=None, limit=None):
91 """Return list of detailed image information."""
92
93=== added file 'nova/tests/test_image.py'
94--- nova/tests/test_image.py 1970-01-01 00:00:00 +0000
95+++ nova/tests/test_image.py 2011-08-05 13:46:49 +0000
96@@ -0,0 +1,132 @@
97+# vim: tabstop=4 shiftwidth=4 softtabstop=4
98+
99+# Copyright 2011 OpenStack LLC
100+# Author: Soren Hansen
101+#
102+# Licensed under the Apache License, Version 2.0 (the "License"); you may
103+# not use this file except in compliance with the License. You may obtain
104+# a copy of the License at
105+#
106+# http://www.apache.org/licenses/LICENSE-2.0
107+#
108+# Unless required by applicable law or agreed to in writing, software
109+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
110+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
111+# License for the specific language governing permissions and limitations
112+# under the License.
113+
114+import datetime
115+
116+from nova import context
117+from nova import exception
118+from nova import test
119+import nova.image
120+
121+class _ImageTestCase(test.TestCase):
122+ def setUp(self):
123+ super(_ImageTestCase, self).setUp()
124+ self.context = context.get_admin_context()
125+
126+ def test_index(self):
127+ res = self.image_service.index(self.context)
128+ for image in res:
129+ self.assertEquals(set(image.keys()), set(['id', 'name']))
130+
131+ def test_detail(self):
132+ res = self.image_service.detail(self.context)
133+ for image in res:
134+ keys = set(image.keys())
135+ self.assertEquals(keys, set(['id', 'name', 'created_at',
136+ 'updated_at', 'deleted_at', 'deleted',
137+ 'status', 'is_public', 'properties']))
138+ self.assertTrue(isinstance(image['created_at'], datetime.datetime))
139+ self.assertTrue(isinstance(image['updated_at'], datetime.datetime))
140+
141+ if not (isinstance(image['deleted_at'], datetime.datetime) or
142+ image['deleted_at'] is None):
143+ self.fail('image\'s "deleted_at" attribute was neither a '
144+ 'datetime object nor None')
145+
146+ def check_is_bool(image, key):
147+ val = image.get('deleted')
148+ if not isinstance(val, bool):
149+ self.fail('image\'s "%s" attribute wasn\'t '
150+ 'a bool: %r' % (key, val))
151+
152+ check_is_bool(image, 'deleted')
153+ check_is_bool(image, 'is_public')
154+
155+ def test_index_and_detail_have_same_results(self):
156+ index = self.image_service.index(self.context)
157+ detail = self.image_service.detail(self.context)
158+ index_set = set([(i['id'], i['name']) for i in index])
159+ detail_set = set([(i['id'], i['name']) for i in detail])
160+ self.assertEqual(index_set, detail_set)
161+
162+ def test_show_raises_imagenotfound_for_invalid_id(self):
163+ self.assertRaises(exception.ImageNotFound,
164+ self.image_service.show,
165+ self.context,
166+ 'this image does not exist')
167+
168+ def test_show_by_name(self):
169+ self.assertRaises(exception.ImageNotFound,
170+ self.image_service.show_by_name,
171+ self.context,
172+ 'this image does not exist')
173+
174+ def test_create_adds_id(self):
175+ index = self.image_service.index(self.context)
176+ image_count = len(index)
177+
178+ self.image_service.create(self.context, {})
179+
180+ index = self.image_service.index(self.context)
181+ self.assertEquals(len(index), image_count + 1)
182+
183+ self.assertTrue(index[0]['id'])
184+
185+ def test_create_keeps_id(self):
186+ self.image_service.create(self.context, {'id': '34'})
187+ self.image_service.show(self.context, '34')
188+
189+ def test_create_rejects_duplicate_ids(self):
190+ self.image_service.create(self.context, {'id': '34'})
191+ self.assertRaises(exception.Duplicate,
192+ self.image_service.create,
193+ self.context,
194+ {'id': '34'})
195+
196+ # Make sure there's still one left
197+ self.image_service.show(self.context, '34')
198+
199+ def test_update(self):
200+ self.image_service.create(self.context,
201+ {'id': '34', 'foo': 'bar'})
202+
203+ self.image_service.update(self.context, '34',
204+ {'id': '34', 'foo': 'baz'})
205+
206+ img = self.image_service.show(self.context, '34')
207+ self.assertEquals(img['foo'], 'baz')
208+
209+ def test_delete(self):
210+ self.image_service.create(self.context, {'id': '34', 'foo': 'bar'})
211+ self.image_service.delete(self.context, '34')
212+ self.assertRaises(exception.NotFound,
213+ self.image_service.show,
214+ self.context,
215+ '34')
216+
217+ def test_delete_all(self):
218+ self.image_service.create(self.context, {'id': '32', 'foo': 'bar'})
219+ self.image_service.create(self.context, {'id': '33', 'foo': 'bar'})
220+ self.image_service.create(self.context, {'id': '34', 'foo': 'bar'})
221+ self.image_service.delete_all()
222+ index = self.image_service.index(self.context)
223+ self.assertEquals(len(index), 0)
224+
225+class FakeImageTestCase(_ImageTestCase):
226+ def setUp(self):
227+ super(FakeImageTestCase, self).setUp()
228+ self.image_service = nova.image.fake.FakeImageService()
229
230=== modified file 'nova/virt/libvirt/connection.py'
231--- nova/virt/libvirt/connection.py 2011-08-05 02:22:13 +0000
232+++ nova/virt/libvirt/connection.py 2011-08-05 13:46:49 +0000
233@@ -392,9 +392,7 @@
234 nova.image.get_image_service(image_href)
235 snapshot = snapshot_image_service.show(context, snapshot_image_id)
236
237- metadata = {'disk_format': base['disk_format'],
238- 'container_format': base['container_format'],
239- 'is_public': False,
240+ metadata = {'is_public': False,
241 'status': 'active',
242 'name': snapshot['name'],
243 'properties': {
244@@ -409,6 +407,12 @@
245 arch = base['properties']['architecture']
246 metadata['properties']['architecture'] = arch
247
248+ if 'disk_format' in base:
249+ metadata['disk_format'] = base['disk_format']
250+
251+ if 'container_format' in base:
252+ metadata['container_format'] = base['container_format']
253+
254 # Make the snapshot
255 snapshot_name = uuid.uuid4().hex
256 snapshot_xml = """