Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / test / images.py @ 039e3e61

History | View | Annotate | Download (13.3 kB)

1 039e3e61 Christos Stavrakakis
# Copyright 2012 GRNET S.A. All rights reserved.
2 039e3e61 Christos Stavrakakis
#
3 039e3e61 Christos Stavrakakis
# Redistribution and use in source and binary forms, with or
4 039e3e61 Christos Stavrakakis
# without modification, are permitted provided that the following
5 039e3e61 Christos Stavrakakis
# conditions are met:
6 039e3e61 Christos Stavrakakis
#
7 039e3e61 Christos Stavrakakis
#   1. Redistributions of source code must retain the above
8 039e3e61 Christos Stavrakakis
#      copyright notice, this list of conditions and the following
9 039e3e61 Christos Stavrakakis
#      disclaimer.
10 039e3e61 Christos Stavrakakis
#
11 039e3e61 Christos Stavrakakis
#   2. Redistributions in binary form must reproduce the above
12 039e3e61 Christos Stavrakakis
#      copyright notice, this list of conditions and the following
13 039e3e61 Christos Stavrakakis
#      disclaimer in the documentation and/or other materials
14 039e3e61 Christos Stavrakakis
#      provided with the distribution.
15 039e3e61 Christos Stavrakakis
#
16 039e3e61 Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 039e3e61 Christos Stavrakakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 039e3e61 Christos Stavrakakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 039e3e61 Christos Stavrakakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 039e3e61 Christos Stavrakakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 039e3e61 Christos Stavrakakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 039e3e61 Christos Stavrakakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 039e3e61 Christos Stavrakakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 039e3e61 Christos Stavrakakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 039e3e61 Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 039e3e61 Christos Stavrakakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 039e3e61 Christos Stavrakakis
# POSSIBILITY OF SUCH DAMAGE.
28 039e3e61 Christos Stavrakakis
#
29 039e3e61 Christos Stavrakakis
# The views and conclusions contained in the software and
30 039e3e61 Christos Stavrakakis
# documentation are those of the authors and should not be
31 039e3e61 Christos Stavrakakis
# interpreted as representing official policies, either expressed
32 039e3e61 Christos Stavrakakis
# or implied, of GRNET S.A.
33 039e3e61 Christos Stavrakakis
34 039e3e61 Christos Stavrakakis
import json
35 039e3e61 Christos Stavrakakis
36 039e3e61 Christos Stavrakakis
from synnefo.api.tests import BaseAPITest
37 039e3e61 Christos Stavrakakis
from synnefo.api.faults import ItemNotFound
38 039e3e61 Christos Stavrakakis
39 039e3e61 Christos Stavrakakis
from mock import patch
40 039e3e61 Christos Stavrakakis
from functools import wraps
41 039e3e61 Christos Stavrakakis
42 039e3e61 Christos Stavrakakis
43 039e3e61 Christos Stavrakakis
def assert_backend_closed(func):
44 039e3e61 Christos Stavrakakis
    """Decorator for ensuring that ImageBackend is returned to pool."""
45 039e3e61 Christos Stavrakakis
    @wraps(func)
46 039e3e61 Christos Stavrakakis
    def wrapper(self, backend):
47 039e3e61 Christos Stavrakakis
        result = func(self, backend)
48 039e3e61 Christos Stavrakakis
        if backend.called is True:
49 039e3e61 Christos Stavrakakis
            backend.return_value.close.assert_called_once_with()
50 039e3e61 Christos Stavrakakis
        return result
51 039e3e61 Christos Stavrakakis
    return wrapper
52 039e3e61 Christos Stavrakakis
53 039e3e61 Christos Stavrakakis
54 039e3e61 Christos Stavrakakis
@patch('synnefo.api.images.ImageBackend')
55 039e3e61 Christos Stavrakakis
class ImageAPITest(BaseAPITest):
56 039e3e61 Christos Stavrakakis
    @assert_backend_closed
57 039e3e61 Christos Stavrakakis
    def test_create_image(self, mimage):
58 039e3e61 Christos Stavrakakis
        """Test that create image is not implemented"""
59 039e3e61 Christos Stavrakakis
        response = self.post('/api/v1.1/images/', 'user', json.dumps(''),
60 039e3e61 Christos Stavrakakis
                             'json')
61 039e3e61 Christos Stavrakakis
        self.assertEqual(response.status_code, 503)
62 039e3e61 Christos Stavrakakis
63 039e3e61 Christos Stavrakakis
    @assert_backend_closed
64 039e3e61 Christos Stavrakakis
    def test_list_images(self, mimage):
65 039e3e61 Christos Stavrakakis
        """Test that expected list of images is returned"""
66 039e3e61 Christos Stavrakakis
        images = [{'id': 1, 'name': 'image-1'},
67 039e3e61 Christos Stavrakakis
                  {'id': 2, 'name': 'image-2'},
68 039e3e61 Christos Stavrakakis
                  {'id': 3, 'name': 'image-3'}]
69 039e3e61 Christos Stavrakakis
        mimage().list.return_value = images
70 039e3e61 Christos Stavrakakis
        response = self.get('/api/v1.1/images/', 'user')
71 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
72 039e3e61 Christos Stavrakakis
        api_images = json.loads(response.content)['images']['values']
73 039e3e61 Christos Stavrakakis
        self.assertEqual(images, api_images)
74 039e3e61 Christos Stavrakakis
75 039e3e61 Christos Stavrakakis
    @assert_backend_closed
76 039e3e61 Christos Stavrakakis
    def test_list_images_detail(self, mimage):
77 039e3e61 Christos Stavrakakis
        images = [{'id': 1,
78 039e3e61 Christos Stavrakakis
                   'name': 'image-1',
79 039e3e61 Christos Stavrakakis
                   'status':'available',
80 039e3e61 Christos Stavrakakis
                   'created_at': '2012-11-26 11:52:54',
81 039e3e61 Christos Stavrakakis
                   'updated_at': '2012-12-26 11:52:54',
82 039e3e61 Christos Stavrakakis
                   'deleted_at': '',
83 039e3e61 Christos Stavrakakis
                   'properties': {'foo':'bar'}},
84 039e3e61 Christos Stavrakakis
                  {'id': 2,
85 039e3e61 Christos Stavrakakis
                   'name': 'image-2',
86 039e3e61 Christos Stavrakakis
                   'status': 'deleted',
87 039e3e61 Christos Stavrakakis
                   'created_at': '2012-11-26 11:52:54',
88 039e3e61 Christos Stavrakakis
                   'updated_at': '2012-12-26 11:52:54',
89 039e3e61 Christos Stavrakakis
                   'deleted_at': '2012-12-27 11:52:54',
90 039e3e61 Christos Stavrakakis
                   'properties': ''},
91 039e3e61 Christos Stavrakakis
                  {'id': 3,
92 039e3e61 Christos Stavrakakis
                   'name': 'image-3',
93 039e3e61 Christos Stavrakakis
                   'status': 'available',
94 039e3e61 Christos Stavrakakis
                   'created_at': '2012-11-26 11:52:54',
95 039e3e61 Christos Stavrakakis
                   'deleted_at': '',
96 039e3e61 Christos Stavrakakis
                   'updated_at': '2012-12-26 11:52:54',
97 039e3e61 Christos Stavrakakis
                   'properties': ''}]
98 039e3e61 Christos Stavrakakis
        result_images = [
99 039e3e61 Christos Stavrakakis
                  {'id': 1,
100 039e3e61 Christos Stavrakakis
                   'name': 'image-1',
101 039e3e61 Christos Stavrakakis
                   'status':'ACTIVE',
102 039e3e61 Christos Stavrakakis
                   'progress': 100,
103 039e3e61 Christos Stavrakakis
                   'created': '2012-11-26T11:52:54+00:00',
104 039e3e61 Christos Stavrakakis
                   'updated': '2012-12-26T11:52:54+00:00',
105 039e3e61 Christos Stavrakakis
                   'metadata': {'values': {'foo':'bar'}}},
106 039e3e61 Christos Stavrakakis
                  {'id': 2,
107 039e3e61 Christos Stavrakakis
                   'name': 'image-2',
108 039e3e61 Christos Stavrakakis
                   'status': 'DELETED',
109 039e3e61 Christos Stavrakakis
                   'progress': 0,
110 039e3e61 Christos Stavrakakis
                   'created': '2012-11-26T11:52:54+00:00',
111 039e3e61 Christos Stavrakakis
                   'updated': '2012-12-26T11:52:54+00:00'},
112 039e3e61 Christos Stavrakakis
                  {'id': 3,
113 039e3e61 Christos Stavrakakis
                   'name': 'image-3',
114 039e3e61 Christos Stavrakakis
                   'status': 'ACTIVE',
115 039e3e61 Christos Stavrakakis
                   'progress': 100,
116 039e3e61 Christos Stavrakakis
                   'created': '2012-11-26T11:52:54+00:00',
117 039e3e61 Christos Stavrakakis
                   'updated': '2012-12-26T11:52:54+00:00'}]
118 039e3e61 Christos Stavrakakis
        mimage().list.return_value = images
119 039e3e61 Christos Stavrakakis
        response = self.get('/api/v1.1/images/detail', 'user')
120 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
121 039e3e61 Christos Stavrakakis
        api_images = json.loads(response.content)['images']['values']
122 039e3e61 Christos Stavrakakis
        self.assertEqual(len(result_images), len(api_images))
123 039e3e61 Christos Stavrakakis
        self.assertEqual(result_images, api_images)
124 039e3e61 Christos Stavrakakis
125 039e3e61 Christos Stavrakakis
    @assert_backend_closed
126 039e3e61 Christos Stavrakakis
    def test_list_images_detail_since(self, mimage):
127 039e3e61 Christos Stavrakakis
        from datetime import datetime, timedelta
128 039e3e61 Christos Stavrakakis
        from time import sleep
129 039e3e61 Christos Stavrakakis
        old_time = datetime.now()
130 039e3e61 Christos Stavrakakis
        new_time = old_time + timedelta(seconds=0.1)
131 039e3e61 Christos Stavrakakis
        sleep(0.1)
132 039e3e61 Christos Stavrakakis
        images = [
133 039e3e61 Christos Stavrakakis
                  {'id': 1,
134 039e3e61 Christos Stavrakakis
                   'name': 'image-1',
135 039e3e61 Christos Stavrakakis
                   'status':'available',
136 039e3e61 Christos Stavrakakis
                   'progress': 100,
137 039e3e61 Christos Stavrakakis
                   'created_at': old_time.isoformat(),
138 039e3e61 Christos Stavrakakis
                   'deleted_at': '',
139 039e3e61 Christos Stavrakakis
                   'updated_at': old_time.isoformat(),
140 039e3e61 Christos Stavrakakis
                   'properties': ''},
141 039e3e61 Christos Stavrakakis
                  {'id': 2,
142 039e3e61 Christos Stavrakakis
                   'name': 'image-2',
143 039e3e61 Christos Stavrakakis
                   'status': 'deleted',
144 039e3e61 Christos Stavrakakis
                   'progress': 0,
145 039e3e61 Christos Stavrakakis
                   'created_at': new_time.isoformat(),
146 039e3e61 Christos Stavrakakis
                   'updated_at': new_time.isoformat(),
147 039e3e61 Christos Stavrakakis
                   'deleted_at': new_time.isoformat(),
148 039e3e61 Christos Stavrakakis
                   'properties': ''}]
149 039e3e61 Christos Stavrakakis
        mimage().iter.return_value = images
150 039e3e61 Christos Stavrakakis
        response =\
151 039e3e61 Christos Stavrakakis
            self.get('/api/v1.1/images/detail?changes-since=%sUTC' % new_time)
152 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
153 039e3e61 Christos Stavrakakis
        api_images = json.loads(response.content)['images']['values']
154 039e3e61 Christos Stavrakakis
        self.assertEqual(1, len(api_images))
155 039e3e61 Christos Stavrakakis
156 039e3e61 Christos Stavrakakis
    @assert_backend_closed
157 039e3e61 Christos Stavrakakis
    def test_get_image_details(self, mimage):
158 039e3e61 Christos Stavrakakis
        image = {'id': 42,
159 039e3e61 Christos Stavrakakis
                 'name': 'image-1',
160 039e3e61 Christos Stavrakakis
                 'status': 'available',
161 039e3e61 Christos Stavrakakis
                 'created_at': '2012-11-26 11:52:54',
162 039e3e61 Christos Stavrakakis
                 'updated_at': '2012-12-26 11:52:54',
163 039e3e61 Christos Stavrakakis
                 'deleted_at': '',
164 039e3e61 Christos Stavrakakis
                 'properties': {'foo': 'bar'}}
165 039e3e61 Christos Stavrakakis
        result_image = \
166 039e3e61 Christos Stavrakakis
                  {'id': 42,
167 039e3e61 Christos Stavrakakis
                   'name': 'image-1',
168 039e3e61 Christos Stavrakakis
                   'status': 'ACTIVE',
169 039e3e61 Christos Stavrakakis
                   'progress': 100,
170 039e3e61 Christos Stavrakakis
                   'created': '2012-11-26T11:52:54+00:00',
171 039e3e61 Christos Stavrakakis
                   'updated': '2012-12-26T11:52:54+00:00',
172 039e3e61 Christos Stavrakakis
                   'metadata': {'values': {'foo': 'bar'}}}
173 039e3e61 Christos Stavrakakis
        with patch('synnefo.api.util.get_image') as m:
174 039e3e61 Christos Stavrakakis
            m.return_value = image
175 039e3e61 Christos Stavrakakis
            response = self.get('/api/v1.1/images/42', 'user')
176 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
177 039e3e61 Christos Stavrakakis
        api_image = json.loads(response.content)['image']
178 039e3e61 Christos Stavrakakis
        self.assertEqual(api_image, result_image)
179 039e3e61 Christos Stavrakakis
180 039e3e61 Christos Stavrakakis
    @assert_backend_closed
181 039e3e61 Christos Stavrakakis
    def test_invalid_image(self, mimage):
182 039e3e61 Christos Stavrakakis
        with patch('synnefo.api.util.get_image') as m:
183 039e3e61 Christos Stavrakakis
            m.side_effect = ItemNotFound('Image not found')
184 039e3e61 Christos Stavrakakis
            response = self.get('/api/v1.1/images/42', 'user')
185 039e3e61 Christos Stavrakakis
        self.assertItemNotFound(response)
186 039e3e61 Christos Stavrakakis
187 039e3e61 Christos Stavrakakis
    def test_delete_image(self, mimage):
188 039e3e61 Christos Stavrakakis
        response = self.delete("/api/v1.1/images/42", "user")
189 039e3e61 Christos Stavrakakis
        self.assertEqual(response.status_code, 204)
190 039e3e61 Christos Stavrakakis
        mimage.return_value.delete.assert_called_once_with('42')
191 039e3e61 Christos Stavrakakis
192 039e3e61 Christos Stavrakakis
193 039e3e61 Christos Stavrakakis
@patch('synnefo.api.util.ImageBackend')
194 039e3e61 Christos Stavrakakis
class ImageMetadataAPITest(BaseAPITest):
195 039e3e61 Christos Stavrakakis
    def setUp(self):
196 039e3e61 Christos Stavrakakis
        self.image = {'id': 42,
197 039e3e61 Christos Stavrakakis
                 'name': 'image-1',
198 039e3e61 Christos Stavrakakis
                 'status': 'available',
199 039e3e61 Christos Stavrakakis
                 'created_at': '2012-11-26 11:52:54',
200 039e3e61 Christos Stavrakakis
                 'updated_at': '2012-12-26 11:52:54',
201 039e3e61 Christos Stavrakakis
                 'deleted_at': '',
202 039e3e61 Christos Stavrakakis
                 'properties': {'foo': 'bar', 'foo2': 'bar2'}}
203 039e3e61 Christos Stavrakakis
        self.result_image = \
204 039e3e61 Christos Stavrakakis
                  {'id': 42,
205 039e3e61 Christos Stavrakakis
                   'name': 'image-1',
206 039e3e61 Christos Stavrakakis
                   'status': 'ACTIVE',
207 039e3e61 Christos Stavrakakis
                   'progress': 100,
208 039e3e61 Christos Stavrakakis
                   'created': '2012-11-26T11:52:54+00:00',
209 039e3e61 Christos Stavrakakis
                   'updated': '2012-12-26T11:52:54+00:00',
210 039e3e61 Christos Stavrakakis
                   'metadata': {'values': {'foo': 'bar'}}}
211 039e3e61 Christos Stavrakakis
212 039e3e61 Christos Stavrakakis
    @assert_backend_closed
213 039e3e61 Christos Stavrakakis
    def test_list_metadata(self, backend):
214 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
215 039e3e61 Christos Stavrakakis
        response = self.get('/api/v1.1/images/42/meta', 'user')
216 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
217 039e3e61 Christos Stavrakakis
        meta = json.loads(response.content)['metadata']['values']
218 039e3e61 Christos Stavrakakis
        self.assertEqual(meta, self.image['properties'])
219 039e3e61 Christos Stavrakakis
220 039e3e61 Christos Stavrakakis
    @assert_backend_closed
221 039e3e61 Christos Stavrakakis
    def test_get_metadata(self, backend):
222 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
223 039e3e61 Christos Stavrakakis
        response = self.get('/api/v1.1/images/42/meta/foo', 'user')
224 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
225 039e3e61 Christos Stavrakakis
        meta = json.loads(response.content)['meta']
226 039e3e61 Christos Stavrakakis
        self.assertEqual(meta['foo'], 'bar')
227 039e3e61 Christos Stavrakakis
228 039e3e61 Christos Stavrakakis
    @assert_backend_closed
229 039e3e61 Christos Stavrakakis
    def test_get_invalid_metadata(self, backend):
230 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
231 039e3e61 Christos Stavrakakis
        response = self.get('/api/v1.1/images/42/meta/not_found', 'user')
232 039e3e61 Christos Stavrakakis
        self.assertItemNotFound(response)
233 039e3e61 Christos Stavrakakis
234 039e3e61 Christos Stavrakakis
    @assert_backend_closed
235 039e3e61 Christos Stavrakakis
    def test_delete_metadata_item(self, backend):
236 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
237 039e3e61 Christos Stavrakakis
        with patch("synnefo.api.images.ImageBackend") as m:
238 039e3e61 Christos Stavrakakis
            response = self.delete('/api/v1.1/images/42/meta/foo', 'user')
239 039e3e61 Christos Stavrakakis
            self.assertEqual(response.status_code, 204)
240 039e3e61 Christos Stavrakakis
            m.return_value.update.assert_called_once_with('42',
241 039e3e61 Christos Stavrakakis
                                        {'properties': {'foo2': 'bar2'}})
242 039e3e61 Christos Stavrakakis
243 039e3e61 Christos Stavrakakis
    @assert_backend_closed
244 039e3e61 Christos Stavrakakis
    def test_create_metadata_item(self, backend):
245 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
246 039e3e61 Christos Stavrakakis
        with patch("synnefo.api.images.ImageBackend") as m:
247 039e3e61 Christos Stavrakakis
                request = {'meta': {'foo3': 'bar3'}}
248 039e3e61 Christos Stavrakakis
                response = self.put('/api/v1.1/images/42/meta/foo3', 'user',
249 039e3e61 Christos Stavrakakis
                                    json.dumps(request), 'json')
250 039e3e61 Christos Stavrakakis
                self.assertEqual(response.status_code, 201)
251 039e3e61 Christos Stavrakakis
                m.return_value.update.assert_called_once_with('42',
252 039e3e61 Christos Stavrakakis
                        {'properties':
253 039e3e61 Christos Stavrakakis
                            {'foo': 'bar', 'foo2': 'bar2', 'foo3': 'bar3'}})
254 039e3e61 Christos Stavrakakis
255 039e3e61 Christos Stavrakakis
    @assert_backend_closed
256 039e3e61 Christos Stavrakakis
    def test_create_metadata_malformed_1(self, backend):
257 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
258 039e3e61 Christos Stavrakakis
        with patch("synnefo.api.images.ImageBackend"):
259 039e3e61 Christos Stavrakakis
                request = {'met': {'foo3': 'bar3'}}
260 039e3e61 Christos Stavrakakis
                response = self.put('/api/v1.1/images/42/meta/foo3', 'user',
261 039e3e61 Christos Stavrakakis
                                    json.dumps(request), 'json')
262 039e3e61 Christos Stavrakakis
                self.assertBadRequest(response)
263 039e3e61 Christos Stavrakakis
264 039e3e61 Christos Stavrakakis
    @assert_backend_closed
265 039e3e61 Christos Stavrakakis
    def test_create_metadata_malformed_2(self, backend):
266 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
267 039e3e61 Christos Stavrakakis
        with patch("synnefo.api.images.ImageBackend"):
268 039e3e61 Christos Stavrakakis
                request = {'meta': [('foo3', 'bar3')]}
269 039e3e61 Christos Stavrakakis
                response = self.put('/api/v1.1/images/42/meta/foo3', 'user',
270 039e3e61 Christos Stavrakakis
                                    json.dumps(request), 'json')
271 039e3e61 Christos Stavrakakis
                self.assertBadRequest(response)
272 039e3e61 Christos Stavrakakis
273 039e3e61 Christos Stavrakakis
    @assert_backend_closed
274 039e3e61 Christos Stavrakakis
    def test_create_metadata_malformed_3(self, backend):
275 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
276 039e3e61 Christos Stavrakakis
        with patch("synnefo.api.images.ImageBackend"):
277 039e3e61 Christos Stavrakakis
            request = {'met': {'foo3': 'bar3', 'foo4': 'bar4'}}
278 039e3e61 Christos Stavrakakis
            response = self.put('/api/v1.1/images/42/meta/foo3', 'user',
279 039e3e61 Christos Stavrakakis
                                    json.dumps(request), 'json')
280 039e3e61 Christos Stavrakakis
            self.assertBadRequest(response)
281 039e3e61 Christos Stavrakakis
282 039e3e61 Christos Stavrakakis
    @assert_backend_closed
283 039e3e61 Christos Stavrakakis
    def test_create_metadata_malformed_4(self, backend):
284 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
285 039e3e61 Christos Stavrakakis
        with patch("synnefo.api.images.ImageBackend"):
286 039e3e61 Christos Stavrakakis
            request = {'met': {'foo3': 'bar3'}}
287 039e3e61 Christos Stavrakakis
            response = self.put('/api/v1.1/images/42/meta/foo4', 'user',
288 039e3e61 Christos Stavrakakis
                                    json.dumps(request), 'json')
289 039e3e61 Christos Stavrakakis
            self.assertBadRequest(response)
290 039e3e61 Christos Stavrakakis
291 039e3e61 Christos Stavrakakis
    @assert_backend_closed
292 039e3e61 Christos Stavrakakis
    def test_update_metadata_item(self, backend):
293 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
294 039e3e61 Christos Stavrakakis
        with patch("synnefo.api.images.ImageBackend") as m:
295 039e3e61 Christos Stavrakakis
                request = {'metadata': {'foo': 'bar_new', 'foo4': 'bar4'}}
296 039e3e61 Christos Stavrakakis
                response = self.post('/api/v1.1/images/42/meta', 'user',
297 039e3e61 Christos Stavrakakis
                                    json.dumps(request), 'json')
298 039e3e61 Christos Stavrakakis
                self.assertEqual(response.status_code, 201)
299 039e3e61 Christos Stavrakakis
                m.return_value.update.assert_called_once_with('42',
300 039e3e61 Christos Stavrakakis
                        {'properties':
301 039e3e61 Christos Stavrakakis
                            {'foo': 'bar_new', 'foo2': 'bar2', 'foo4': 'bar4'}
302 039e3e61 Christos Stavrakakis
                        })
303 039e3e61 Christos Stavrakakis
304 039e3e61 Christos Stavrakakis
    @assert_backend_closed
305 039e3e61 Christos Stavrakakis
    def test_update_metadata_malformed(self, backend):
306 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
307 039e3e61 Christos Stavrakakis
        with patch("synnefo.api.images.ImageBackend"):
308 039e3e61 Christos Stavrakakis
                request = {'meta': {'foo': 'bar_new', 'foo4': 'bar4'}}
309 039e3e61 Christos Stavrakakis
                response = self.post('/api/v1.1/images/42/meta', 'user',
310 039e3e61 Christos Stavrakakis
                                    json.dumps(request), 'json')
311 039e3e61 Christos Stavrakakis
                self.assertBadRequest(response)