1
# Copyright 2011 Denali Systems, Inc.
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
16
from lxml import etree
19
from nova.api.openstack.volume import snapshots
21
from nova import exception
22
from nova import flags
23
from nova.openstack.common import log as logging
24
from nova.openstack.common import timeutils
26
from nova.tests.api.openstack import fakes
27
from nova import volume
31
LOG = logging.getLogger(__name__)
34
def _get_default_snapshot_param():
38
'status': 'available',
41
'display_name': 'Default name',
42
'display_description': 'Default description',
46
def stub_snapshot_create(self, context, volume_id, name, description):
47
snapshot = _get_default_snapshot_param()
48
snapshot['volume_id'] = volume_id
49
snapshot['display_name'] = name
50
snapshot['display_description'] = description
54
def stub_snapshot_delete(self, context, snapshot):
55
if snapshot['id'] != 123:
56
raise exception.NotFound
59
def stub_snapshot_get(self, context, snapshot_id):
60
if snapshot_id != 123:
61
raise exception.NotFound
63
param = _get_default_snapshot_param()
67
def stub_snapshot_get_all(self, context, search_opts=None):
68
param = _get_default_snapshot_param()
72
class SnapshotApiTest(test.TestCase):
74
super(SnapshotApiTest, self).setUp()
75
self.controller = snapshots.SnapshotsController()
77
self.stubs.Set(db, 'snapshot_get_all_by_project',
78
fakes.stub_snapshot_get_all_by_project)
79
self.stubs.Set(db, 'snapshot_get_all',
80
fakes.stub_snapshot_get_all)
82
def test_snapshot_create(self):
83
self.stubs.Set(volume.api.API, "create_snapshot", stub_snapshot_create)
84
self.stubs.Set(volume.api.API, 'get', fakes.stub_volume_get)
85
snapshot = {"volume_id": '12',
87
"display_name": "Snapshot Test Name",
88
"display_description": "Snapshot Test Desc"}
89
body = dict(snapshot=snapshot)
90
req = fakes.HTTPRequest.blank('/v1/snapshots')
91
resp_dict = self.controller.create(req, body)
93
self.assertTrue('snapshot' in resp_dict)
94
self.assertEqual(resp_dict['snapshot']['display_name'],
95
snapshot['display_name'])
96
self.assertEqual(resp_dict['snapshot']['display_description'],
97
snapshot['display_description'])
99
def test_snapshot_create_force(self):
100
self.stubs.Set(volume.api.API, "create_snapshot_force",
101
stub_snapshot_create)
102
self.stubs.Set(volume.api.API, 'get', fakes.stub_volume_get)
103
snapshot = {"volume_id": '12',
105
"display_name": "Snapshot Test Name",
106
"display_description": "Snapshot Test Desc"}
107
body = dict(snapshot=snapshot)
108
req = fakes.HTTPRequest.blank('/v1/snapshots')
109
resp_dict = self.controller.create(req, body)
111
self.assertTrue('snapshot' in resp_dict)
112
self.assertEqual(resp_dict['snapshot']['display_name'],
113
snapshot['display_name'])
114
self.assertEqual(resp_dict['snapshot']['display_description'],
115
snapshot['display_description'])
117
# Test invalid force paramter
118
snapshot = {"volume_id": 12,
119
"force": '**&&^^%%$$##@@'}
120
body = dict(snapshot=snapshot)
121
req = fakes.HTTPRequest.blank('/v1/snapshots')
122
self.assertRaises(exception.InvalidParameterValue,
123
self.controller.create,
127
def test_snapshot_delete(self):
128
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
129
self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete)
132
req = fakes.HTTPRequest.blank('/v1/snapshots/%d' % snapshot_id)
133
resp = self.controller.delete(req, snapshot_id)
134
self.assertEqual(resp.status_int, 202)
136
def test_snapshot_delete_invalid_id(self):
137
self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete)
139
req = fakes.HTTPRequest.blank('/v1/snapshots/%d' % snapshot_id)
140
self.assertRaises(webob.exc.HTTPNotFound,
141
self.controller.delete,
145
def test_snapshot_show(self):
146
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
147
req = fakes.HTTPRequest.blank('/v1/snapshots/123')
148
resp_dict = self.controller.show(req, 123)
150
self.assertTrue('snapshot' in resp_dict)
151
self.assertEqual(resp_dict['snapshot']['id'], '123')
153
def test_snapshot_show_invalid_id(self):
155
req = fakes.HTTPRequest.blank('/v1/snapshots/%d' % snapshot_id)
156
self.assertRaises(webob.exc.HTTPNotFound,
157
self.controller.show,
161
def test_snapshot_detail(self):
162
self.stubs.Set(volume.api.API, "get_all_snapshots",
163
stub_snapshot_get_all)
164
req = fakes.HTTPRequest.blank('/v1/snapshots/detail')
165
resp_dict = self.controller.detail(req)
167
self.assertTrue('snapshots' in resp_dict)
168
resp_snapshots = resp_dict['snapshots']
169
self.assertEqual(len(resp_snapshots), 1)
171
resp_snapshot = resp_snapshots.pop()
172
self.assertEqual(resp_snapshot['id'], '123')
174
def test_admin_list_snapshots_limited_to_project(self):
175
req = fakes.HTTPRequest.blank('/v1/fake/snapshots',
176
use_admin_context=True)
177
res = self.controller.index(req)
179
self.assertTrue('snapshots' in res)
180
self.assertEqual(1, len(res['snapshots']))
182
def test_admin_list_snapshots_all_tenants(self):
183
req = fakes.HTTPRequest.blank('/v1/fake/snapshots?all_tenants=1',
184
use_admin_context=True)
185
res = self.controller.index(req)
186
self.assertTrue('snapshots' in res)
187
self.assertEqual(3, len(res['snapshots']))
189
def test_all_tenants_non_admin_gets_all_tenants(self):
190
req = fakes.HTTPRequest.blank('/v1/fake/snapshots?all_tenants=1')
191
res = self.controller.index(req)
192
self.assertTrue('snapshots' in res)
193
self.assertEqual(1, len(res['snapshots']))
195
def test_non_admin_get_by_project(self):
196
req = fakes.HTTPRequest.blank('/v1/fake/snapshots')
197
res = self.controller.index(req)
198
self.assertTrue('snapshots' in res)
199
self.assertEqual(1, len(res['snapshots']))
202
class SnapshotSerializerTest(test.TestCase):
203
def _verify_snapshot(self, snap, tree):
204
self.assertEqual(tree.tag, 'snapshot')
206
for attr in ('id', 'status', 'size', 'created_at',
207
'display_name', 'display_description', 'volume_id'):
208
self.assertEqual(str(snap[attr]), tree.get(attr))
210
def test_snapshot_show_create_serializer(self):
211
serializer = snapshots.SnapshotTemplate()
214
status='snap_status',
216
created_at=timeutils.utcnow(),
217
display_name='snap_name',
218
display_description='snap_desc',
221
text = serializer.serialize(dict(snapshot=raw_snapshot))
224
tree = etree.fromstring(text)
226
self._verify_snapshot(raw_snapshot, tree)
228
def test_snapshot_index_detail_serializer(self):
229
serializer = snapshots.SnapshotsTemplate()
230
raw_snapshots = [dict(
232
status='snap1_status',
234
created_at=timeutils.utcnow(),
235
display_name='snap1_name',
236
display_description='snap1_desc',
241
status='snap2_status',
243
created_at=timeutils.utcnow(),
244
display_name='snap2_name',
245
display_description='snap2_desc',
248
text = serializer.serialize(dict(snapshots=raw_snapshots))
251
tree = etree.fromstring(text)
253
self.assertEqual('snapshots', tree.tag)
254
self.assertEqual(len(raw_snapshots), len(tree))
255
for idx, child in enumerate(tree):
256
self._verify_snapshot(raw_snapshots[idx], child)
259
class SnapshotsUnprocessableEntityTestCase(test.TestCase):
262
Tests of places we throw 422 Unprocessable Entity from
266
super(SnapshotsUnprocessableEntityTestCase, self).setUp()
267
self.controller = snapshots.SnapshotsController()
269
def _unprocessable_snapshot_create(self, body):
270
req = fakes.HTTPRequest.blank('/v2/fake/snapshots')
273
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
274
self.controller.create, req, body)
276
def test_create_no_body(self):
277
self._unprocessable_snapshot_create(body=None)
279
def test_create_missing_snapshot(self):
280
body = {'foo': {'a': 'b'}}
281
self._unprocessable_snapshot_create(body=body)
283
def test_create_malformed_entity(self):
284
body = {'snapshot': 'string'}
285
self._unprocessable_snapshot_create(body=body)