~0x44/nova/extdoc

« back to all changes in this revision

Viewing changes to nova/tests/api/openstack/test_images.py

  • Committer: Tarmac
  • Author(s): Brian Waldon
  • Date: 2011-09-13 15:23:15 UTC
  • mfrom: (1517.2.17 image-service-cleanup)
  • Revision ID: tarmac-20110913152315-a21jg0bvjjlyga82
- remove translation of non-recognized attributes to user metadata, now just ignored
- ensure all keys are defined in image dictionaries, defaulting to None if glance client doesn't provide one
- remove BaseImageService
- reorganize some GlanceImageService tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
import copy
24
24
import json
25
 
import os
26
 
import shutil
27
 
import tempfile
28
25
import xml.dom.minidom as minidom
29
26
 
30
27
import mox
31
28
import stubout
32
29
import webob
33
30
 
34
 
from glance import client as glance_client
35
31
from nova import context
36
 
from nova import exception
37
 
from nova import test
38
 
from nova import utils
39
32
import nova.api.openstack
40
33
from nova.api.openstack import images
 
34
from nova import test
41
35
from nova.tests.api.openstack import fakes
42
36
 
43
37
 
44
 
class _BaseImageServiceTests(test.TestCase):
45
 
    """Tasks to test for all image services"""
46
 
 
47
 
    def __init__(self, *args, **kwargs):
48
 
        super(_BaseImageServiceTests, self).__init__(*args, **kwargs)
49
 
        self.service = None
50
 
        self.context = None
51
 
 
52
 
    def test_create(self):
53
 
        fixture = self._make_fixture('test image')
54
 
        num_images = len(self.service.index(self.context))
55
 
 
56
 
        image_id = self.service.create(self.context, fixture)['id']
57
 
 
58
 
        self.assertNotEquals(None, image_id)
59
 
        self.assertEquals(num_images + 1,
60
 
                          len(self.service.index(self.context)))
61
 
 
62
 
    def test_create_and_show_non_existing_image(self):
63
 
        fixture = self._make_fixture('test image')
64
 
        num_images = len(self.service.index(self.context))
65
 
 
66
 
        image_id = self.service.create(self.context, fixture)['id']
67
 
 
68
 
        self.assertNotEquals(None, image_id)
69
 
        self.assertRaises(exception.NotFound,
70
 
                          self.service.show,
71
 
                          self.context,
72
 
                          'bad image id')
73
 
 
74
 
    def test_create_and_show_non_existing_image_by_name(self):
75
 
        fixture = self._make_fixture('test image')
76
 
        num_images = len(self.service.index(self.context))
77
 
 
78
 
        image_id = self.service.create(self.context, fixture)['id']
79
 
 
80
 
        self.assertNotEquals(None, image_id)
81
 
        self.assertRaises(exception.ImageNotFound,
82
 
                          self.service.show_by_name,
83
 
                          self.context,
84
 
                          'bad image id')
85
 
 
86
 
    def test_update(self):
87
 
        fixture = self._make_fixture('test image')
88
 
        image_id = self.service.create(self.context, fixture)['id']
89
 
        fixture['status'] = 'in progress'
90
 
 
91
 
        self.service.update(self.context, image_id, fixture)
92
 
 
93
 
        new_image_data = self.service.show(self.context, image_id)
94
 
        self.assertEquals('in progress', new_image_data['status'])
95
 
 
96
 
    def test_delete(self):
97
 
        fixture1 = self._make_fixture('test image 1')
98
 
        fixture2 = self._make_fixture('test image 2')
99
 
        fixtures = [fixture1, fixture2]
100
 
 
101
 
        num_images = len(self.service.index(self.context))
102
 
        self.assertEquals(0, num_images, str(self.service.index(self.context)))
103
 
 
104
 
        ids = []
105
 
        for fixture in fixtures:
106
 
            new_id = self.service.create(self.context, fixture)['id']
107
 
            ids.append(new_id)
108
 
 
109
 
        num_images = len(self.service.index(self.context))
110
 
        self.assertEquals(2, num_images, str(self.service.index(self.context)))
111
 
 
112
 
        self.service.delete(self.context, ids[0])
113
 
 
114
 
        num_images = len(self.service.index(self.context))
115
 
        self.assertEquals(1, num_images)
116
 
 
117
 
    def test_index(self):
118
 
        fixture = self._make_fixture('test image')
119
 
        image_id = self.service.create(self.context, fixture)['id']
120
 
        image_metas = self.service.index(self.context)
121
 
        expected = [{'id': 'DONTCARE', 'name': 'test image'}]
122
 
        self.assertDictListMatch(image_metas, expected)
123
 
 
124
 
    @staticmethod
125
 
    def _make_fixture(name):
126
 
        fixture = {'name': name,
127
 
                   'updated': None,
128
 
                   'created': None,
129
 
                   'status': None,
130
 
                   'is_public': True}
131
 
        return fixture
132
 
 
133
 
 
134
 
class GlanceImageServiceTest(_BaseImageServiceTests):
135
 
 
136
 
    """Tests the Glance image service, in particular that metadata translation
137
 
    works properly.
138
 
 
139
 
    At a high level, the translations involved are:
140
 
 
141
 
        1. Glance -> ImageService - This is needed so we can support
142
 
           multple ImageServices (Glance, Local, etc)
143
 
 
144
 
        2. ImageService -> API - This is needed so we can support multple
145
 
           APIs (OpenStack, EC2)
146
 
    """
147
 
    def setUp(self):
148
 
        super(GlanceImageServiceTest, self).setUp()
149
 
        self.stubs = stubout.StubOutForTesting()
150
 
        fakes.stub_out_glance(self.stubs)
151
 
        fakes.stub_out_compute_api_snapshot(self.stubs)
152
 
        service_class = 'nova.image.glance.GlanceImageService'
153
 
        self.service = utils.import_object(service_class)
154
 
        self.context = context.RequestContext('fake', 'fake')
155
 
        self.service.delete_all()
156
 
        self.sent_to_glance = {}
157
 
        fakes.stub_out_glance_add_image(self.stubs, self.sent_to_glance)
158
 
 
159
 
    def tearDown(self):
160
 
        self.stubs.UnsetAll()
161
 
        super(GlanceImageServiceTest, self).tearDown()
162
 
 
163
 
    def test_create_with_instance_id(self):
164
 
        """Ensure instance_id is persisted as an image-property"""
165
 
        fixture = {'name': 'test image',
166
 
                   'is_public': False,
167
 
                   'properties': {'instance_id': '42', 'user_id': 'fake'}}
168
 
 
169
 
        image_id = self.service.create(self.context, fixture)['id']
170
 
        expected = fixture
171
 
        self.assertDictMatch(self.sent_to_glance['metadata'], expected)
172
 
 
173
 
        image_meta = self.service.show(self.context, image_id)
174
 
        expected = {'id': image_id,
175
 
                    'name': 'test image',
176
 
                    'is_public': False,
177
 
                    'properties': {'instance_id': '42', 'user_id': 'fake'}}
178
 
        self.assertDictMatch(image_meta, expected)
179
 
 
180
 
        image_metas = self.service.detail(self.context)
181
 
        self.assertDictMatch(image_metas[0], expected)
182
 
 
183
 
    def test_create_without_instance_id(self):
184
 
        """
185
 
        Ensure we can create an image without having to specify an
186
 
        instance_id. Public images are an example of an image not tied to an
187
 
        instance.
188
 
        """
189
 
        fixture = {'name': 'test image'}
190
 
        image_id = self.service.create(self.context, fixture)['id']
191
 
 
192
 
        expected = {'name': 'test image', 'properties': {}}
193
 
        self.assertDictMatch(self.sent_to_glance['metadata'], expected)
194
 
 
195
 
    def test_index_default_limit(self):
196
 
        fixtures = []
197
 
        ids = []
198
 
        for i in range(10):
199
 
            fixture = self._make_fixture('TestImage %d' % (i))
200
 
            fixtures.append(fixture)
201
 
            ids.append(self.service.create(self.context, fixture)['id'])
202
 
 
203
 
        image_metas = self.service.index(self.context)
204
 
        i = 0
205
 
        for meta in image_metas:
206
 
            expected = {'id': 'DONTCARE',
207
 
                        'name': 'TestImage %d' % (i)}
208
 
            self.assertDictMatch(meta, expected)
209
 
            i = i + 1
210
 
 
211
 
    def test_index_marker(self):
212
 
        fixtures = []
213
 
        ids = []
214
 
        for i in range(10):
215
 
            fixture = self._make_fixture('TestImage %d' % (i))
216
 
            fixtures.append(fixture)
217
 
            ids.append(self.service.create(self.context, fixture)['id'])
218
 
 
219
 
        image_metas = self.service.index(self.context, marker=ids[1])
220
 
        self.assertEquals(len(image_metas), 8)
221
 
        i = 2
222
 
        for meta in image_metas:
223
 
            expected = {'id': 'DONTCARE',
224
 
                        'name': 'TestImage %d' % (i)}
225
 
            self.assertDictMatch(meta, expected)
226
 
            i = i + 1
227
 
 
228
 
    def test_index_limit(self):
229
 
        fixtures = []
230
 
        ids = []
231
 
        for i in range(10):
232
 
            fixture = self._make_fixture('TestImage %d' % (i))
233
 
            fixtures.append(fixture)
234
 
            ids.append(self.service.create(self.context, fixture)['id'])
235
 
 
236
 
        image_metas = self.service.index(self.context, limit=3)
237
 
        self.assertEquals(len(image_metas), 3)
238
 
 
239
 
    def test_index_marker_and_limit(self):
240
 
        fixtures = []
241
 
        ids = []
242
 
        for i in range(10):
243
 
            fixture = self._make_fixture('TestImage %d' % (i))
244
 
            fixtures.append(fixture)
245
 
            ids.append(self.service.create(self.context, fixture)['id'])
246
 
 
247
 
        image_metas = self.service.index(self.context, marker=ids[3], limit=1)
248
 
        self.assertEquals(len(image_metas), 1)
249
 
        i = 4
250
 
        for meta in image_metas:
251
 
            expected = {'id': 'DONTCARE',
252
 
                        'name': 'TestImage %d' % (i)}
253
 
            self.assertDictMatch(meta, expected)
254
 
            i = i + 1
255
 
 
256
 
    def test_detail_marker(self):
257
 
        fixtures = []
258
 
        ids = []
259
 
        for i in range(10):
260
 
            fixture = self._make_fixture('TestImage %d' % (i))
261
 
            fixtures.append(fixture)
262
 
            ids.append(self.service.create(self.context, fixture)['id'])
263
 
 
264
 
        image_metas = self.service.detail(self.context, marker=ids[1])
265
 
        self.assertEquals(len(image_metas), 8)
266
 
        i = 2
267
 
        for meta in image_metas:
268
 
            expected = {
269
 
                'id': 'DONTCARE',
270
 
                'status': None,
271
 
                'is_public': True,
272
 
                'name': 'TestImage %d' % (i),
273
 
                'properties': {
274
 
                    'updated': None,
275
 
                    'created': None,
276
 
                },
277
 
            }
278
 
 
279
 
            self.assertDictMatch(meta, expected)
280
 
            i = i + 1
281
 
 
282
 
    def test_detail_limit(self):
283
 
        fixtures = []
284
 
        ids = []
285
 
        for i in range(10):
286
 
            fixture = self._make_fixture('TestImage %d' % (i))
287
 
            fixtures.append(fixture)
288
 
            ids.append(self.service.create(self.context, fixture)['id'])
289
 
 
290
 
        image_metas = self.service.detail(self.context, limit=3)
291
 
        self.assertEquals(len(image_metas), 3)
292
 
 
293
 
    def test_detail_marker_and_limit(self):
294
 
        fixtures = []
295
 
        ids = []
296
 
        for i in range(10):
297
 
            fixture = self._make_fixture('TestImage %d' % (i))
298
 
            fixtures.append(fixture)
299
 
            ids.append(self.service.create(self.context, fixture)['id'])
300
 
 
301
 
        image_metas = self.service.detail(self.context, marker=ids[3], limit=3)
302
 
        self.assertEquals(len(image_metas), 3)
303
 
        i = 4
304
 
        for meta in image_metas:
305
 
            expected = {
306
 
                'id': 'DONTCARE',
307
 
                'status': None,
308
 
                'is_public': True,
309
 
                'name': 'TestImage %d' % (i),
310
 
                'properties': {
311
 
                    'updated': None, 'created': None},
312
 
            }
313
 
            self.assertDictMatch(meta, expected)
314
 
            i = i + 1
315
 
 
316
 
 
317
 
class ImageControllerWithGlanceServiceTest(test.TestCase):
 
38
NOW_API_FORMAT = "2010-10-11T10:30:22Z"
 
39
 
 
40
 
 
41
class ImagesTest(test.TestCase):
318
42
    """
319
43
    Test of the OpenStack API /images application controller w/Glance.
320
44
    """
321
 
    NOW_GLANCE_FORMAT = "2010-10-11T10:30:22"
322
 
    NOW_API_FORMAT = "2010-10-11T10:30:22Z"
323
45
 
324
46
    def setUp(self):
325
47
        """Run before each test."""
326
 
        super(ImageControllerWithGlanceServiceTest, self).setUp()
327
 
        self.flags(image_service='nova.image.glance.GlanceImageService')
 
48
        super(ImagesTest, self).setUp()
328
49
        self.stubs = stubout.StubOutForTesting()
329
50
        fakes.stub_out_networking(self.stubs)
330
51
        fakes.stub_out_rate_limiting(self.stubs)
331
52
        fakes.stub_out_key_pair_funcs(self.stubs)
332
 
        self.fixtures = self._make_image_fixtures()
333
 
        fakes.stub_out_glance(self.stubs, initial_fixtures=self.fixtures)
334
53
        fakes.stub_out_compute_api_snapshot(self.stubs)
335
54
        fakes.stub_out_compute_api_backup(self.stubs)
 
55
        fakes.stub_out_glance(self.stubs)
336
56
 
337
57
    def tearDown(self):
338
58
        """Run after each test."""
339
59
        self.stubs.UnsetAll()
340
 
        super(ImageControllerWithGlanceServiceTest, self).tearDown()
 
60
        super(ImagesTest, self).tearDown()
341
61
 
342
62
    def _get_fake_context(self):
343
63
        class Context(object):
344
64
            project_id = 'fake'
 
65
            auth_token = True
345
66
        return Context()
346
67
 
347
 
    def _applicable_fixture(self, fixture, user_id):
348
 
        """Determine if this fixture is applicable for given user id."""
349
 
        is_public = fixture["is_public"]
350
 
        try:
351
 
            uid = fixture["properties"]["user_id"]
352
 
        except KeyError:
353
 
            uid = None
354
 
        return uid == user_id or is_public
355
 
 
356
68
    def test_get_image_index(self):
357
69
        request = webob.Request.blank('/v1.0/images')
358
 
        response = request.get_response(fakes.wsgi_app())
 
70
        app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
 
71
        response = request.get_response(app)
359
72
 
360
73
        response_dict = json.loads(response.body)
361
74
        response_list = response_dict["images"]
362
75
 
363
 
        expected = [{'id': 123, 'name': 'public image'},
364
 
                    {'id': 124, 'name': 'queued snapshot'},
365
 
                    {'id': 125, 'name': 'saving snapshot'},
366
 
                    {'id': 126, 'name': 'active snapshot'},
367
 
                    {'id': 127, 'name': 'killed snapshot'},
368
 
                    {'id': 128, 'name': 'deleted snapshot'},
369
 
                    {'id': 129, 'name': 'pending_delete snapshot'},
370
 
                    {'id': 131, 'name': None}]
 
76
        expected = [{'id': '123', 'name': 'public image'},
 
77
                    {'id': '124', 'name': 'queued snapshot'},
 
78
                    {'id': '125', 'name': 'saving snapshot'},
 
79
                    {'id': '126', 'name': 'active snapshot'},
 
80
                    {'id': '127', 'name': 'killed snapshot'},
 
81
                    {'id': '128', 'name': 'deleted snapshot'},
 
82
                    {'id': '129', 'name': 'pending_delete snapshot'},
 
83
                    {'id': '130', 'name': None}]
371
84
 
372
85
        self.assertDictListMatch(response_list, expected)
373
86
 
374
87
    def test_get_image(self):
375
88
        request = webob.Request.blank('/v1.0/images/123')
376
 
        response = request.get_response(fakes.wsgi_app())
 
89
        app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
 
90
        response = request.get_response(app)
377
91
 
378
92
        self.assertEqual(200, response.status_int)
379
93
 
381
95
 
382
96
        expected_image = {
383
97
            "image": {
384
 
                "id": 123,
 
98
                "id": "123",
385
99
                "name": "public image",
386
 
                "updated": self.NOW_API_FORMAT,
387
 
                "created": self.NOW_API_FORMAT,
 
100
                "updated": NOW_API_FORMAT,
 
101
                "created": NOW_API_FORMAT,
388
102
                "status": "ACTIVE",
389
103
                "progress": 100,
390
104
            },
391
105
        }
392
106
 
393
 
        self.assertEqual(expected_image, actual_image)
 
107
        self.assertDictMatch(expected_image, actual_image)
394
108
 
395
109
    def test_get_image_v1_1(self):
396
110
        request = webob.Request.blank('/v1.1/fake/images/124')
397
 
        response = request.get_response(fakes.wsgi_app())
 
111
        app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
 
112
        response = request.get_response(app)
398
113
 
399
114
        actual_image = json.loads(response.body)
400
115
 
405
120
 
406
121
        expected_image = {
407
122
            "image": {
408
 
                "id": 124,
 
123
                "id": "124",
409
124
                "name": "queued snapshot",
410
 
                "updated": self.NOW_API_FORMAT,
411
 
                "created": self.NOW_API_FORMAT,
 
125
                "updated": NOW_API_FORMAT,
 
126
                "created": NOW_API_FORMAT,
412
127
                "status": "SAVING",
413
128
                "progress": 0,
414
129
                'server': {
442
157
    def test_get_image_xml(self):
443
158
        request = webob.Request.blank('/v1.0/images/123')
444
159
        request.accept = "application/xml"
445
 
        response = request.get_response(fakes.wsgi_app())
 
160
        app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
 
161
        response = request.get_response(app)
446
162
 
447
163
        actual_image = minidom.parseString(response.body.replace("  ", ""))
448
164
 
449
 
        expected_now = self.NOW_API_FORMAT
 
165
        expected_now = NOW_API_FORMAT
450
166
        expected_image = minidom.parseString("""
451
167
            <image id="123"
452
168
                    name="public image"
460
176
        self.assertEqual(expected_image.toxml(), actual_image.toxml())
461
177
 
462
178
    def test_get_image_xml_no_name(self):
463
 
        request = webob.Request.blank('/v1.0/images/131')
 
179
        request = webob.Request.blank('/v1.0/images/130')
464
180
        request.accept = "application/xml"
465
 
        response = request.get_response(fakes.wsgi_app())
 
181
        app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
 
182
        response = request.get_response(app)
466
183
 
467
184
        actual_image = minidom.parseString(response.body.replace("  ", ""))
468
185
 
469
 
        expected_now = self.NOW_API_FORMAT
 
186
        expected_now = NOW_API_FORMAT
470
187
        expected_image = minidom.parseString("""
471
 
            <image id="131"
 
188
            <image id="130"
472
189
                    name="None"
473
190
                    updated="%(expected_now)s"
474
191
                    created="%(expected_now)s"
553
270
 
554
271
    def test_get_image_index_v1_1(self):
555
272
        request = webob.Request.blank('/v1.1/fake/images')
556
 
        response = request.get_response(fakes.wsgi_app())
 
273
        app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
 
274
        response = request.get_response(app)
557
275
 
558
276
        response_dict = json.loads(response.body)
559
277
        response_list = response_dict["images"]
560
278
 
561
 
        fixtures = copy.copy(self.fixtures)
562
 
 
563
 
        for image in fixtures:
564
 
            if not self._applicable_fixture(image, "fake"):
565
 
                fixtures.remove(image)
566
 
                continue
567
 
 
568
 
            href = "http://localhost/v1.1/fake/images/%s" % image["id"]
569
 
            bookmark = "http://localhost/fake/images/%s" % image["id"]
570
 
            test_image = {
571
 
                "id": image["id"],
572
 
                "name": image["name"],
573
 
                "links": [
574
 
                    {
575
 
                        "rel": "self",
576
 
                        "href": href,
577
 
                    },
578
 
                    {
579
 
                        "rel": "bookmark",
580
 
                        "href": bookmark,
581
 
                    },
582
 
                ],
583
 
            }
584
 
            self.assertTrue(test_image in response_list)
585
 
 
586
 
        self.assertEqual(len(response_list), len(fixtures))
 
279
        expected = [
 
280
            {
 
281
                "id": "123",
 
282
                "name": "public image",
 
283
                "links": [
 
284
                    {
 
285
                        "rel": "self",
 
286
                        "href": "http://localhost/v1.1/fake/images/123",
 
287
                    },
 
288
                    {
 
289
                        "rel": "bookmark",
 
290
                        "href": "http://localhost/fake/images/123",
 
291
                    },
 
292
                ],
 
293
            },
 
294
            {
 
295
                "id": "124",
 
296
                "name": "queued snapshot",
 
297
                "links": [
 
298
                    {
 
299
                        "rel": "self",
 
300
                        "href": "http://localhost/v1.1/fake/images/124",
 
301
                    },
 
302
                    {
 
303
                        "rel": "bookmark",
 
304
                        "href": "http://localhost/fake/images/124",
 
305
                    },
 
306
                ],
 
307
            },
 
308
            {
 
309
                "id": "125",
 
310
                "name": "saving snapshot",
 
311
                "links": [
 
312
                    {
 
313
                        "rel": "self",
 
314
                        "href": "http://localhost/v1.1/fake/images/125",
 
315
                    },
 
316
                    {
 
317
                        "rel": "bookmark",
 
318
                        "href": "http://localhost/fake/images/125",
 
319
                    },
 
320
                ],
 
321
            },
 
322
            {
 
323
                "id": "126",
 
324
                "name": "active snapshot",
 
325
                "links": [
 
326
                    {
 
327
                        "rel": "self",
 
328
                        "href": "http://localhost/v1.1/fake/images/126",
 
329
                    },
 
330
                    {
 
331
                        "rel": "bookmark",
 
332
                        "href": "http://localhost/fake/images/126",
 
333
                    },
 
334
                ],
 
335
            },
 
336
            {
 
337
                "id": "127",
 
338
                "name": "killed snapshot",
 
339
                "links": [
 
340
                    {
 
341
                        "rel": "self",
 
342
                        "href": "http://localhost/v1.1/fake/images/127",
 
343
                    },
 
344
                    {
 
345
                        "rel": "bookmark",
 
346
                        "href": "http://localhost/fake/images/127",
 
347
                    },
 
348
                ],
 
349
            },
 
350
            {
 
351
                "id": "128",
 
352
                "name": "deleted snapshot",
 
353
                "links": [
 
354
                    {
 
355
                        "rel": "self",
 
356
                        "href": "http://localhost/v1.1/fake/images/128",
 
357
                    },
 
358
                    {
 
359
                        "rel": "bookmark",
 
360
                        "href": "http://localhost/fake/images/128",
 
361
                    },
 
362
                ],
 
363
            },
 
364
            {
 
365
                "id": "129",
 
366
                "name": "pending_delete snapshot",
 
367
                "links": [
 
368
                    {
 
369
                        "rel": "self",
 
370
                        "href": "http://localhost/v1.1/fake/images/129",
 
371
                    },
 
372
                    {
 
373
                        "rel": "bookmark",
 
374
                        "href": "http://localhost/fake/images/129",
 
375
                    },
 
376
                ],
 
377
            },
 
378
            {
 
379
                "id": "130",
 
380
                "name": None,
 
381
                "links": [
 
382
                    {
 
383
                        "rel": "self",
 
384
                        "href": "http://localhost/v1.1/fake/images/130",
 
385
                    },
 
386
                    {
 
387
                        "rel": "bookmark",
 
388
                        "href": "http://localhost/fake/images/130",
 
389
                    },
 
390
                ],
 
391
            },
 
392
        ]
 
393
 
 
394
        self.assertDictListMatch(response_list, expected)
587
395
 
588
396
    def test_get_image_details(self):
589
397
        request = webob.Request.blank('/v1.0/images/detail')
590
 
        response = request.get_response(fakes.wsgi_app())
 
398
        app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
 
399
        response = request.get_response(app)
591
400
 
592
401
        response_dict = json.loads(response.body)
593
402
        response_list = response_dict["images"]
594
403
 
595
404
        expected = [{
596
 
            'id': 123,
 
405
            'id': '123',
597
406
            'name': 'public image',
598
 
            'updated': self.NOW_API_FORMAT,
599
 
            'created': self.NOW_API_FORMAT,
 
407
            'updated': NOW_API_FORMAT,
 
408
            'created': NOW_API_FORMAT,
600
409
            'status': 'ACTIVE',
601
410
            'progress': 100,
602
411
        },
603
412
        {
604
 
            'id': 124,
 
413
            'id': '124',
605
414
            'name': 'queued snapshot',
606
 
            'updated': self.NOW_API_FORMAT,
607
 
            'created': self.NOW_API_FORMAT,
 
415
            'updated': NOW_API_FORMAT,
 
416
            'created': NOW_API_FORMAT,
608
417
            'status': 'SAVING',
609
418
            'progress': 0,
610
419
        },
611
420
        {
612
 
            'id': 125,
 
421
            'id': '125',
613
422
            'name': 'saving snapshot',
614
 
            'updated': self.NOW_API_FORMAT,
615
 
            'created': self.NOW_API_FORMAT,
 
423
            'updated': NOW_API_FORMAT,
 
424
            'created': NOW_API_FORMAT,
616
425
            'status': 'SAVING',
617
426
            'progress': 0,
618
427
        },
619
428
        {
620
 
            'id': 126,
 
429
            'id': '126',
621
430
            'name': 'active snapshot',
622
 
            'updated': self.NOW_API_FORMAT,
623
 
            'created': self.NOW_API_FORMAT,
 
431
            'updated': NOW_API_FORMAT,
 
432
            'created': NOW_API_FORMAT,
624
433
            'status': 'ACTIVE',
625
434
            'progress': 100,
626
435
        },
627
436
        {
628
 
            'id': 127,
 
437
            'id': '127',
629
438
            'name': 'killed snapshot',
630
 
            'updated': self.NOW_API_FORMAT,
631
 
            'created': self.NOW_API_FORMAT,
 
439
            'updated': NOW_API_FORMAT,
 
440
            'created': NOW_API_FORMAT,
632
441
            'status': 'ERROR',
633
442
            'progress': 0,
634
443
        },
635
444
        {
636
 
            'id': 128,
 
445
            'id': '128',
637
446
            'name': 'deleted snapshot',
638
 
            'updated': self.NOW_API_FORMAT,
639
 
            'created': self.NOW_API_FORMAT,
 
447
            'updated': NOW_API_FORMAT,
 
448
            'created': NOW_API_FORMAT,
640
449
            'status': 'DELETED',
641
450
            'progress': 0,
642
451
        },
643
452
        {
644
 
            'id': 129,
 
453
            'id': '129',
645
454
            'name': 'pending_delete snapshot',
646
 
            'updated': self.NOW_API_FORMAT,
647
 
            'created': self.NOW_API_FORMAT,
 
455
            'updated': NOW_API_FORMAT,
 
456
            'created': NOW_API_FORMAT,
648
457
            'status': 'DELETED',
649
458
            'progress': 0,
650
459
        },
651
460
        {
652
 
            'id': 131,
 
461
            'id': '130',
653
462
            'name': None,
654
 
            'updated': self.NOW_API_FORMAT,
655
 
            'created': self.NOW_API_FORMAT,
 
463
            'updated': NOW_API_FORMAT,
 
464
            'created': NOW_API_FORMAT,
656
465
            'status': 'ACTIVE',
657
466
            'progress': 100,
658
467
        }]
661
470
 
662
471
    def test_get_image_details_v1_1(self):
663
472
        request = webob.Request.blank('/v1.1/fake/images/detail')
664
 
        response = request.get_response(fakes.wsgi_app())
 
473
        app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
 
474
        response = request.get_response(app)
665
475
 
666
476
        response_dict = json.loads(response.body)
667
477
        response_list = response_dict["images"]
669
479
        server_bookmark = "http://localhost/servers/42"
670
480
 
671
481
        expected = [{
672
 
            'id': 123,
 
482
            'id': '123',
673
483
            'name': 'public image',
674
 
            'metadata': {},
675
 
            'updated': self.NOW_API_FORMAT,
676
 
            'created': self.NOW_API_FORMAT,
 
484
            'metadata': {'key1': 'value1'},
 
485
            'updated': NOW_API_FORMAT,
 
486
            'created': NOW_API_FORMAT,
677
487
            'status': 'ACTIVE',
678
488
            'progress': 100,
679
489
            "links": [{
686
496
            }],
687
497
        },
688
498
        {
689
 
            'id': 124,
 
499
            'id': '124',
690
500
            'name': 'queued snapshot',
691
501
            'metadata': {
692
502
                u'instance_ref': u'http://localhost/v1.1/servers/42',
693
503
                u'user_id': u'fake',
694
504
            },
695
 
            'updated': self.NOW_API_FORMAT,
696
 
            'created': self.NOW_API_FORMAT,
 
505
            'updated': NOW_API_FORMAT,
 
506
            'created': NOW_API_FORMAT,
697
507
            'status': 'SAVING',
698
508
            'progress': 0,
699
509
            'server': {
717
527
            }],
718
528
        },
719
529
        {
720
 
            'id': 125,
 
530
            'id': '125',
721
531
            'name': 'saving snapshot',
722
532
            'metadata': {
723
533
                u'instance_ref': u'http://localhost/v1.1/servers/42',
724
534
                u'user_id': u'fake',
725
535
            },
726
 
            'updated': self.NOW_API_FORMAT,
727
 
            'created': self.NOW_API_FORMAT,
 
536
            'updated': NOW_API_FORMAT,
 
537
            'created': NOW_API_FORMAT,
728
538
            'status': 'SAVING',
729
539
            'progress': 0,
730
540
            'server': {
748
558
            }],
749
559
        },
750
560
        {
751
 
            'id': 126,
 
561
            'id': '126',
752
562
            'name': 'active snapshot',
753
563
            'metadata': {
754
564
                u'instance_ref': u'http://localhost/v1.1/servers/42',
755
565
                u'user_id': u'fake',
756
566
            },
757
 
            'updated': self.NOW_API_FORMAT,
758
 
            'created': self.NOW_API_FORMAT,
 
567
            'updated': NOW_API_FORMAT,
 
568
            'created': NOW_API_FORMAT,
759
569
            'status': 'ACTIVE',
760
570
            'progress': 100,
761
571
            'server': {
779
589
            }],
780
590
        },
781
591
        {
782
 
            'id': 127,
 
592
            'id': '127',
783
593
            'name': 'killed snapshot',
784
594
            'metadata': {
785
595
                u'instance_ref': u'http://localhost/v1.1/servers/42',
786
596
                u'user_id': u'fake',
787
597
            },
788
 
            'updated': self.NOW_API_FORMAT,
789
 
            'created': self.NOW_API_FORMAT,
 
598
            'updated': NOW_API_FORMAT,
 
599
            'created': NOW_API_FORMAT,
790
600
            'status': 'ERROR',
791
601
            'progress': 0,
792
602
            'server': {
810
620
            }],
811
621
        },
812
622
        {
813
 
            'id': 128,
 
623
            'id': '128',
814
624
            'name': 'deleted snapshot',
815
625
            'metadata': {
816
626
                u'instance_ref': u'http://localhost/v1.1/servers/42',
817
627
                u'user_id': u'fake',
818
628
            },
819
 
            'updated': self.NOW_API_FORMAT,
820
 
            'created': self.NOW_API_FORMAT,
 
629
            'updated': NOW_API_FORMAT,
 
630
            'created': NOW_API_FORMAT,
821
631
            'status': 'DELETED',
822
632
            'progress': 0,
823
633
            'server': {
841
651
            }],
842
652
        },
843
653
        {
844
 
            'id': 129,
 
654
            'id': '129',
845
655
            'name': 'pending_delete snapshot',
846
656
            'metadata': {
847
657
                u'instance_ref': u'http://localhost/v1.1/servers/42',
848
658
                u'user_id': u'fake',
849
659
            },
850
 
            'updated': self.NOW_API_FORMAT,
851
 
            'created': self.NOW_API_FORMAT,
 
660
            'updated': NOW_API_FORMAT,
 
661
            'created': NOW_API_FORMAT,
852
662
            'status': 'DELETED',
853
663
            'progress': 0,
854
664
            'server': {
872
682
            }],
873
683
        },
874
684
        {
875
 
            'id': 131,
 
685
            'id': '130',
876
686
            'name': None,
877
687
            'metadata': {},
878
 
            'updated': self.NOW_API_FORMAT,
879
 
            'created': self.NOW_API_FORMAT,
 
688
            'updated': NOW_API_FORMAT,
 
689
            'created': NOW_API_FORMAT,
880
690
            'status': 'ACTIVE',
881
691
            'progress': 100,
882
692
            "links": [{
883
693
                "rel": "self",
884
 
                "href": "http://localhost/v1.1/fake/images/131",
 
694
                "href": "http://localhost/v1.1/fake/images/130",
885
695
            },
886
696
            {
887
697
                "rel": "bookmark",
888
 
                "href": "http://localhost/fake/images/131",
 
698
                "href": "http://localhost/fake/images/130",
889
699
            }],
890
700
        },
891
701
        ]
1097
907
 
1098
908
    def test_get_image_found(self):
1099
909
        req = webob.Request.blank('/v1.0/images/123')
1100
 
        res = req.get_response(fakes.wsgi_app())
 
910
        app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
 
911
        res = req.get_response(app)
1101
912
        image_meta = json.loads(res.body)['image']
1102
 
        expected = {'id': 123, 'name': 'public image',
1103
 
                    'updated': self.NOW_API_FORMAT,
1104
 
                    'created': self.NOW_API_FORMAT, 'status': 'ACTIVE',
 
913
        expected = {'id': '123', 'name': 'public image',
 
914
                    'updated': NOW_API_FORMAT,
 
915
                    'created': NOW_API_FORMAT, 'status': 'ACTIVE',
1105
916
                    'progress': 100}
1106
917
        self.assertDictMatch(image_meta, expected)
1107
918
 
1110
921
        res = req.get_response(fakes.wsgi_app())
1111
922
        self.assertEqual(res.status_int, 404)
1112
923
 
1113
 
    def test_get_image_not_owned(self):
1114
 
        """We should return a 404 if we request an image that doesn't belong
1115
 
        to us
1116
 
        """
1117
 
        req = webob.Request.blank('/v1.0/images/130')
1118
 
        res = req.get_response(fakes.wsgi_app())
1119
 
        self.assertEqual(res.status_int, 404)
1120
 
 
1121
924
    def test_create_image(self):
1122
925
        body = dict(image=dict(serverId='123', name='Snapshot 1'))
1123
926
        req = webob.Request.blank('/v1.0/images')
1160
963
        response = req.get_response(fakes.wsgi_app())
1161
964
        self.assertEqual(400, response.status_int)
1162
965
 
1163
 
    @classmethod
1164
 
    def _make_image_fixtures(cls):
1165
 
        image_id = 123
1166
 
        base_attrs = {'created_at': cls.NOW_GLANCE_FORMAT,
1167
 
                      'updated_at': cls.NOW_GLANCE_FORMAT,
1168
 
                      'deleted_at': None,
1169
 
                      'deleted': False}
1170
 
 
1171
 
        fixtures = []
1172
 
 
1173
 
        def add_fixture(**kwargs):
1174
 
            kwargs.update(base_attrs)
1175
 
            fixtures.append(kwargs)
1176
 
 
1177
 
        # Public image
1178
 
        add_fixture(id=image_id, name='public image', is_public=True,
1179
 
                    status='active', properties={})
1180
 
        image_id += 1
1181
 
 
1182
 
        # Snapshot for User 1
1183
 
        server_ref = 'http://localhost/v1.1/servers/42'
1184
 
        snapshot_properties = {'instance_ref': server_ref, 'user_id': 'fake'}
1185
 
        statuses = ('queued', 'saving', 'active','killed',
1186
 
                    'deleted', 'pending_delete')
1187
 
        for status in statuses:
1188
 
            add_fixture(id=image_id, name='%s snapshot' % status,
1189
 
                        is_public=False, status=status,
1190
 
                        properties=snapshot_properties)
1191
 
            image_id += 1
1192
 
 
1193
 
        # Snapshot for User 2
1194
 
        other_snapshot_properties = {'instance_id': '43', 'user_id': 'other'}
1195
 
        add_fixture(id=image_id, name='someone elses snapshot',
1196
 
                    is_public=False, status='active',
1197
 
                    properties=other_snapshot_properties)
1198
 
 
1199
 
        image_id += 1
1200
 
 
1201
 
        # Image without a name
1202
 
        add_fixture(id=image_id, is_public=True, status='active',
1203
 
                    properties={})
1204
 
        image_id += 1
1205
 
 
1206
 
        return fixtures
1207
 
 
1208
966
 
1209
967
class ImageXMLSerializationTest(test.TestCase):
1210
968