Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / tests / images.py @ d984eedc

History | View | Annotate | Download (16.5 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 bd40abfa Christos Stavrakakis
from snf_django.lib.api import faults
37 d2b8ec7b Christos Stavrakakis
from snf_django.utils.testing import BaseAPITest
38 dc99330c Georgios D. Tsoukalas
from synnefo.lib.services import get_service_path
39 dc99330c Georgios D. Tsoukalas
from synnefo.cyclades_settings import cyclades_services
40 dc99330c Georgios D. Tsoukalas
from synnefo.lib import join_urls
41 039e3e61 Christos Stavrakakis
42 039e3e61 Christos Stavrakakis
from mock import patch
43 039e3e61 Christos Stavrakakis
from functools import wraps
44 039e3e61 Christos Stavrakakis
45 039e3e61 Christos Stavrakakis
46 039e3e61 Christos Stavrakakis
def assert_backend_closed(func):
47 039e3e61 Christos Stavrakakis
    """Decorator for ensuring that ImageBackend is returned to pool."""
48 039e3e61 Christos Stavrakakis
    @wraps(func)
49 039e3e61 Christos Stavrakakis
    def wrapper(self, backend):
50 039e3e61 Christos Stavrakakis
        result = func(self, backend)
51 039e3e61 Christos Stavrakakis
        if backend.called is True:
52 184a2a8c Christos Stavrakakis
            backend.return_value.close.asssert_called
53 039e3e61 Christos Stavrakakis
        return result
54 039e3e61 Christos Stavrakakis
    return wrapper
55 039e3e61 Christos Stavrakakis
56 039e3e61 Christos Stavrakakis
57 dc99330c Georgios D. Tsoukalas
class ComputeAPITest(BaseAPITest):
58 dc99330c Georgios D. Tsoukalas
    def setUp(self, *args, **kwargs):
59 dc99330c Georgios D. Tsoukalas
        super(ComputeAPITest, self).setUp(*args, **kwargs)
60 dc99330c Georgios D. Tsoukalas
        self.compute_path = get_service_path(cyclades_services, 'compute',
61 dc99330c Georgios D. Tsoukalas
                                             version='v2.0')
62 dc99330c Georgios D. Tsoukalas
    def myget(self, path, *args, **kwargs):
63 dc99330c Georgios D. Tsoukalas
        path = join_urls(self.compute_path, path)
64 dc99330c Georgios D. Tsoukalas
        return self.get(path, *args, **kwargs)
65 dc99330c Georgios D. Tsoukalas
66 dc99330c Georgios D. Tsoukalas
    def myput(self, path, *args, **kwargs):
67 dc99330c Georgios D. Tsoukalas
        path = join_urls(self.compute_path, path)
68 dc99330c Georgios D. Tsoukalas
        return self.put(path, *args, **kwargs)
69 dc99330c Georgios D. Tsoukalas
70 dc99330c Georgios D. Tsoukalas
    def mypost(self, path, *args, **kwargs):
71 dc99330c Georgios D. Tsoukalas
        path = join_urls(self.compute_path, path)
72 dc99330c Georgios D. Tsoukalas
        return self.post(path, *args, **kwargs)
73 dc99330c Georgios D. Tsoukalas
74 dc99330c Georgios D. Tsoukalas
    def mydelete(self, path, *args, **kwargs):
75 dc99330c Georgios D. Tsoukalas
        path = join_urls(self.compute_path, path)
76 dc99330c Georgios D. Tsoukalas
        return self.delete(path, *args, **kwargs)
77 dc99330c Georgios D. Tsoukalas
78 dc99330c Georgios D. Tsoukalas
79 cda71050 Christos Stavrakakis
@patch('synnefo.plankton.backend.ImageBackend')
80 dc99330c Georgios D. Tsoukalas
class ImageAPITest(ComputeAPITest):
81 039e3e61 Christos Stavrakakis
    @assert_backend_closed
82 039e3e61 Christos Stavrakakis
    def test_create_image(self, mimage):
83 039e3e61 Christos Stavrakakis
        """Test that create image is not implemented"""
84 dc99330c Georgios D. Tsoukalas
        response = self.mypost('images/', 'user', json.dumps(''), 'json')
85 bd40abfa Christos Stavrakakis
        self.assertEqual(response.status_code, 501)
86 039e3e61 Christos Stavrakakis
87 039e3e61 Christos Stavrakakis
    @assert_backend_closed
88 039e3e61 Christos Stavrakakis
    def test_list_images(self, mimage):
89 039e3e61 Christos Stavrakakis
        """Test that expected list of images is returned"""
90 039e3e61 Christos Stavrakakis
        images = [{'id': 1, 'name': 'image-1'},
91 039e3e61 Christos Stavrakakis
                  {'id': 2, 'name': 'image-2'},
92 039e3e61 Christos Stavrakakis
                  {'id': 3, 'name': 'image-3'}]
93 14c94c48 Christos Stavrakakis
        mimage().list_images.return_value = images
94 dc99330c Georgios D. Tsoukalas
        response = self.myget('images', 'user')
95 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
96 2d04422f Christos Stavrakakis
        api_images = json.loads(response.content)['images']
97 039e3e61 Christos Stavrakakis
        self.assertEqual(images, api_images)
98 039e3e61 Christos Stavrakakis
99 039e3e61 Christos Stavrakakis
    @assert_backend_closed
100 039e3e61 Christos Stavrakakis
    def test_list_images_detail(self, mimage):
101 3768eb67 Christos Stavrakakis
        self.maxDiff = None
102 039e3e61 Christos Stavrakakis
        images = [{'id': 1,
103 039e3e61 Christos Stavrakakis
                   'name': 'image-1',
104 d984eedc Christos Stavrakakis
                   'status': 'available',
105 039e3e61 Christos Stavrakakis
                   'created_at': '2012-11-26 11:52:54',
106 039e3e61 Christos Stavrakakis
                   'updated_at': '2012-12-26 11:52:54',
107 936e0be3 Christos Stavrakakis
                   'owner': 'user1',
108 039e3e61 Christos Stavrakakis
                   'deleted_at': '',
109 3768eb67 Christos Stavrakakis
                   'is_snapshot': False,
110 d984eedc Christos Stavrakakis
                   'is_public': True,
111 d984eedc Christos Stavrakakis
                   'properties': {'foo': 'bar'}},
112 039e3e61 Christos Stavrakakis
                  {'id': 2,
113 039e3e61 Christos Stavrakakis
                   'name': 'image-2',
114 039e3e61 Christos Stavrakakis
                   'status': 'deleted',
115 039e3e61 Christos Stavrakakis
                   'created_at': '2012-11-26 11:52:54',
116 039e3e61 Christos Stavrakakis
                   'updated_at': '2012-12-26 11:52:54',
117 936e0be3 Christos Stavrakakis
                   'owner': 'user1',
118 039e3e61 Christos Stavrakakis
                   'deleted_at': '2012-12-27 11:52:54',
119 3768eb67 Christos Stavrakakis
                   'is_snapshot': False,
120 d984eedc Christos Stavrakakis
                   'is_public': True,
121 039e3e61 Christos Stavrakakis
                   'properties': ''},
122 039e3e61 Christos Stavrakakis
                  {'id': 3,
123 039e3e61 Christos Stavrakakis
                   'name': 'image-3',
124 039e3e61 Christos Stavrakakis
                   'status': 'available',
125 039e3e61 Christos Stavrakakis
                   'created_at': '2012-11-26 11:52:54',
126 039e3e61 Christos Stavrakakis
                   'deleted_at': '',
127 039e3e61 Christos Stavrakakis
                   'updated_at': '2012-12-26 11:52:54',
128 936e0be3 Christos Stavrakakis
                   'owner': 'user1',
129 3768eb67 Christos Stavrakakis
                   'is_snapshot': False,
130 d984eedc Christos Stavrakakis
                   'is_public': False,
131 039e3e61 Christos Stavrakakis
                   'properties': ''}]
132 039e3e61 Christos Stavrakakis
        result_images = [
133 039e3e61 Christos Stavrakakis
                  {'id': 1,
134 039e3e61 Christos Stavrakakis
                   'name': 'image-1',
135 d984eedc Christos Stavrakakis
                   'status': 'ACTIVE',
136 039e3e61 Christos Stavrakakis
                   'progress': 100,
137 039e3e61 Christos Stavrakakis
                   'created': '2012-11-26T11:52:54+00:00',
138 039e3e61 Christos Stavrakakis
                   'updated': '2012-12-26T11:52:54+00:00',
139 936e0be3 Christos Stavrakakis
                   'user_id': 'user1',
140 c25cf3ea Christos Stavrakakis
                   'tenant_id': 'user1',
141 3768eb67 Christos Stavrakakis
                   'is_snapshot': False,
142 d984eedc Christos Stavrakakis
                   'public': True,
143 d984eedc Christos Stavrakakis
                   'metadata': {'foo': 'bar'}},
144 039e3e61 Christos Stavrakakis
                  {'id': 2,
145 039e3e61 Christos Stavrakakis
                   'name': 'image-2',
146 039e3e61 Christos Stavrakakis
                   'status': 'DELETED',
147 039e3e61 Christos Stavrakakis
                   'progress': 0,
148 936e0be3 Christos Stavrakakis
                   'user_id': 'user1',
149 c25cf3ea Christos Stavrakakis
                   'tenant_id': 'user1',
150 039e3e61 Christos Stavrakakis
                   'created': '2012-11-26T11:52:54+00:00',
151 936e0be3 Christos Stavrakakis
                   'updated': '2012-12-26T11:52:54+00:00',
152 3768eb67 Christos Stavrakakis
                   'is_snapshot': False,
153 d984eedc Christos Stavrakakis
                   'public': True,
154 936e0be3 Christos Stavrakakis
                   'metadata': {}},
155 039e3e61 Christos Stavrakakis
                  {'id': 3,
156 039e3e61 Christos Stavrakakis
                   'name': 'image-3',
157 039e3e61 Christos Stavrakakis
                   'status': 'ACTIVE',
158 039e3e61 Christos Stavrakakis
                   'progress': 100,
159 936e0be3 Christos Stavrakakis
                   'user_id': 'user1',
160 c25cf3ea Christos Stavrakakis
                   'tenant_id': 'user1',
161 039e3e61 Christos Stavrakakis
                   'created': '2012-11-26T11:52:54+00:00',
162 936e0be3 Christos Stavrakakis
                   'updated': '2012-12-26T11:52:54+00:00',
163 3768eb67 Christos Stavrakakis
                   'is_snapshot': False,
164 d984eedc Christos Stavrakakis
                   'public': False,
165 936e0be3 Christos Stavrakakis
                   'metadata': {}}]
166 14c94c48 Christos Stavrakakis
        mimage().list_images.return_value = images
167 dc99330c Georgios D. Tsoukalas
        response = self.myget('images/detail', 'user')
168 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
169 2d04422f Christos Stavrakakis
        api_images = json.loads(response.content)['images']
170 039e3e61 Christos Stavrakakis
        self.assertEqual(len(result_images), len(api_images))
171 c25cf3ea Christos Stavrakakis
        map(lambda image: image.pop("links"), api_images)
172 039e3e61 Christos Stavrakakis
        self.assertEqual(result_images, api_images)
173 039e3e61 Christos Stavrakakis
174 039e3e61 Christos Stavrakakis
    @assert_backend_closed
175 039e3e61 Christos Stavrakakis
    def test_list_images_detail_since(self, mimage):
176 039e3e61 Christos Stavrakakis
        from datetime import datetime, timedelta
177 039e3e61 Christos Stavrakakis
        from time import sleep
178 039e3e61 Christos Stavrakakis
        old_time = datetime.now()
179 039e3e61 Christos Stavrakakis
        new_time = old_time + timedelta(seconds=0.1)
180 039e3e61 Christos Stavrakakis
        sleep(0.1)
181 039e3e61 Christos Stavrakakis
        images = [
182 039e3e61 Christos Stavrakakis
                  {'id': 1,
183 039e3e61 Christos Stavrakakis
                   'name': 'image-1',
184 d984eedc Christos Stavrakakis
                   'status': 'available',
185 039e3e61 Christos Stavrakakis
                   'progress': 100,
186 039e3e61 Christos Stavrakakis
                   'created_at': old_time.isoformat(),
187 039e3e61 Christos Stavrakakis
                   'deleted_at': '',
188 039e3e61 Christos Stavrakakis
                   'updated_at': old_time.isoformat(),
189 936e0be3 Christos Stavrakakis
                   'owner': 'user1',
190 3768eb67 Christos Stavrakakis
                   'is_snapshot': False,
191 d984eedc Christos Stavrakakis
                   'is_public': True,
192 039e3e61 Christos Stavrakakis
                   'properties': ''},
193 039e3e61 Christos Stavrakakis
                  {'id': 2,
194 039e3e61 Christos Stavrakakis
                   'name': 'image-2',
195 039e3e61 Christos Stavrakakis
                   'status': 'deleted',
196 039e3e61 Christos Stavrakakis
                   'progress': 0,
197 936e0be3 Christos Stavrakakis
                   'owner': 'user2',
198 039e3e61 Christos Stavrakakis
                   'created_at': new_time.isoformat(),
199 039e3e61 Christos Stavrakakis
                   'updated_at': new_time.isoformat(),
200 039e3e61 Christos Stavrakakis
                   'deleted_at': new_time.isoformat(),
201 3768eb67 Christos Stavrakakis
                   'is_snapshot': False,
202 d984eedc Christos Stavrakakis
                   'is_public': False,
203 039e3e61 Christos Stavrakakis
                   'properties': ''}]
204 14c94c48 Christos Stavrakakis
        mimage().list_images.return_value = images
205 039e3e61 Christos Stavrakakis
        response =\
206 dc99330c Georgios D. Tsoukalas
            self.myget('images/detail?changes-since=%sUTC' % new_time)
207 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
208 2d04422f Christos Stavrakakis
        api_images = json.loads(response.content)['images']
209 039e3e61 Christos Stavrakakis
        self.assertEqual(1, len(api_images))
210 039e3e61 Christos Stavrakakis
211 039e3e61 Christos Stavrakakis
    @assert_backend_closed
212 039e3e61 Christos Stavrakakis
    def test_get_image_details(self, mimage):
213 3768eb67 Christos Stavrakakis
        self.maxDiff = None
214 039e3e61 Christos Stavrakakis
        image = {'id': 42,
215 039e3e61 Christos Stavrakakis
                 'name': 'image-1',
216 039e3e61 Christos Stavrakakis
                 'status': 'available',
217 039e3e61 Christos Stavrakakis
                 'created_at': '2012-11-26 11:52:54',
218 039e3e61 Christos Stavrakakis
                 'updated_at': '2012-12-26 11:52:54',
219 039e3e61 Christos Stavrakakis
                 'deleted_at': '',
220 936e0be3 Christos Stavrakakis
                 'owner': 'user1',
221 3768eb67 Christos Stavrakakis
                 'is_snapshot': False,
222 d984eedc Christos Stavrakakis
                 'is_public': True,
223 039e3e61 Christos Stavrakakis
                 'properties': {'foo': 'bar'}}
224 039e3e61 Christos Stavrakakis
        result_image = \
225 039e3e61 Christos Stavrakakis
                  {'id': 42,
226 039e3e61 Christos Stavrakakis
                   'name': 'image-1',
227 039e3e61 Christos Stavrakakis
                   'status': 'ACTIVE',
228 039e3e61 Christos Stavrakakis
                   'progress': 100,
229 039e3e61 Christos Stavrakakis
                   'created': '2012-11-26T11:52:54+00:00',
230 039e3e61 Christos Stavrakakis
                   'updated': '2012-12-26T11:52:54+00:00',
231 936e0be3 Christos Stavrakakis
                   'user_id': 'user1',
232 c25cf3ea Christos Stavrakakis
                   'tenant_id': 'user1',
233 3768eb67 Christos Stavrakakis
                   'is_snapshot': False,
234 d984eedc Christos Stavrakakis
                   'public': True,
235 2d04422f Christos Stavrakakis
                   'metadata': {'foo': 'bar'}}
236 cda71050 Christos Stavrakakis
        mimage.return_value.get_image.return_value = image
237 dc99330c Georgios D. Tsoukalas
        response = self.myget('images/42', 'user')
238 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
239 039e3e61 Christos Stavrakakis
        api_image = json.loads(response.content)['image']
240 c25cf3ea Christos Stavrakakis
        api_image.pop("links")
241 039e3e61 Christos Stavrakakis
        self.assertEqual(api_image, result_image)
242 039e3e61 Christos Stavrakakis
243 039e3e61 Christos Stavrakakis
    @assert_backend_closed
244 039e3e61 Christos Stavrakakis
    def test_invalid_image(self, mimage):
245 d984eedc Christos Stavrakakis
        mimage.return_value.get_image.side_effect = \
246 d984eedc Christos Stavrakakis
            faults.ItemNotFound('Image not found')
247 dc99330c Georgios D. Tsoukalas
        response = self.myget('images/42', 'user')
248 039e3e61 Christos Stavrakakis
        self.assertItemNotFound(response)
249 039e3e61 Christos Stavrakakis
250 cda71050 Christos Stavrakakis
    @assert_backend_closed
251 039e3e61 Christos Stavrakakis
    def test_delete_image(self, mimage):
252 dc99330c Georgios D. Tsoukalas
        response = self.mydelete("images/42", "user")
253 039e3e61 Christos Stavrakakis
        self.assertEqual(response.status_code, 204)
254 f13aab5d Christos Stavrakakis
        mimage.return_value.unregister.assert_called_once_with('42')
255 f13aab5d Christos Stavrakakis
        mimage.return_value._delete.assert_not_called('42')
256 039e3e61 Christos Stavrakakis
257 a3accf03 Georgios D. Tsoukalas
    @assert_backend_closed
258 a3accf03 Georgios D. Tsoukalas
    def test_catch_wrong_api_paths(self, *args):
259 a3accf03 Georgios D. Tsoukalas
        response = self.myget('nonexistent')
260 a3accf03 Georgios D. Tsoukalas
        self.assertEqual(response.status_code, 400)
261 a3accf03 Georgios D. Tsoukalas
        try:
262 d984eedc Christos Stavrakakis
            json.loads(response.content)
263 a3accf03 Georgios D. Tsoukalas
        except ValueError:
264 a3accf03 Georgios D. Tsoukalas
            self.assertTrue(False)
265 a3accf03 Georgios D. Tsoukalas
266 16437e4d Kostas Papadimitriou
    @assert_backend_closed
267 16437e4d Kostas Papadimitriou
    def test_method_not_allowed(self, *args):
268 16437e4d Kostas Papadimitriou
        # /images/ allows only POST, GET
269 16437e4d Kostas Papadimitriou
        response = self.myput('images', '', '')
270 16437e4d Kostas Papadimitriou
        self.assertMethodNotAllowed(response)
271 16437e4d Kostas Papadimitriou
        response = self.mydelete('images')
272 16437e4d Kostas Papadimitriou
        self.assertMethodNotAllowed(response)
273 16437e4d Kostas Papadimitriou
274 16437e4d Kostas Papadimitriou
        # /images/<imgid>/ allows only GET, DELETE
275 16437e4d Kostas Papadimitriou
        response = self.mypost("images/42")
276 16437e4d Kostas Papadimitriou
        self.assertMethodNotAllowed(response)
277 16437e4d Kostas Papadimitriou
        response = self.myput('images/42', '', '')
278 16437e4d Kostas Papadimitriou
        self.assertMethodNotAllowed(response)
279 16437e4d Kostas Papadimitriou
280 16437e4d Kostas Papadimitriou
        # /images/<imgid>/metadata/ allows only POST, GET
281 16437e4d Kostas Papadimitriou
        response = self.myput('images/42/metadata', '', '')
282 16437e4d Kostas Papadimitriou
        self.assertMethodNotAllowed(response)
283 16437e4d Kostas Papadimitriou
        response = self.mydelete('images/42/metadata')
284 16437e4d Kostas Papadimitriou
        self.assertMethodNotAllowed(response)
285 16437e4d Kostas Papadimitriou
286 16437e4d Kostas Papadimitriou
        # /images/<imgid>/metadata/ allows only POST, GET
287 16437e4d Kostas Papadimitriou
        response = self.myput('images/42/metadata', '', '')
288 16437e4d Kostas Papadimitriou
        self.assertMethodNotAllowed(response)
289 16437e4d Kostas Papadimitriou
        response = self.mydelete('images/42/metadata')
290 16437e4d Kostas Papadimitriou
        self.assertMethodNotAllowed(response)
291 16437e4d Kostas Papadimitriou
292 16437e4d Kostas Papadimitriou
        # /images/<imgid>/metadata/<key> allows only PUT, GET, DELETE
293 16437e4d Kostas Papadimitriou
        response = self.mypost('images/42/metadata/foo')
294 16437e4d Kostas Papadimitriou
        self.assertMethodNotAllowed(response)
295 16437e4d Kostas Papadimitriou
296 039e3e61 Christos Stavrakakis
297 cda71050 Christos Stavrakakis
@patch('synnefo.plankton.backend.ImageBackend')
298 dc99330c Georgios D. Tsoukalas
class ImageMetadataAPITest(ComputeAPITest):
299 039e3e61 Christos Stavrakakis
    def setUp(self):
300 039e3e61 Christos Stavrakakis
        self.image = {'id': 42,
301 d984eedc Christos Stavrakakis
                      'name': 'image-1',
302 d984eedc Christos Stavrakakis
                      'status': 'available',
303 d984eedc Christos Stavrakakis
                      'created_at': '2012-11-26 11:52:54',
304 d984eedc Christos Stavrakakis
                      'updated_at': '2012-12-26 11:52:54',
305 d984eedc Christos Stavrakakis
                      'deleted_at': '',
306 d984eedc Christos Stavrakakis
                      'properties': {'foo': 'bar', 'foo2': 'bar2'}}
307 039e3e61 Christos Stavrakakis
        self.result_image = \
308 d984eedc Christos Stavrakakis
            {'id': 42,
309 d984eedc Christos Stavrakakis
             'name': 'image-1',
310 d984eedc Christos Stavrakakis
             'status': 'ACTIVE',
311 d984eedc Christos Stavrakakis
             'progress': 100,
312 d984eedc Christos Stavrakakis
             'created': '2012-11-26T11:52:54+00:00',
313 d984eedc Christos Stavrakakis
             'updated': '2012-12-26T11:52:54+00:00',
314 d984eedc Christos Stavrakakis
             'metadata': {'foo': 'bar'}}
315 dc99330c Georgios D. Tsoukalas
        super(ImageMetadataAPITest, self).setUp()
316 039e3e61 Christos Stavrakakis
317 039e3e61 Christos Stavrakakis
    @assert_backend_closed
318 039e3e61 Christos Stavrakakis
    def test_list_metadata(self, backend):
319 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
320 dc99330c Georgios D. Tsoukalas
        response = self.myget('images/42/metadata', 'user')
321 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
322 2d04422f Christos Stavrakakis
        meta = json.loads(response.content)['metadata']
323 039e3e61 Christos Stavrakakis
        self.assertEqual(meta, self.image['properties'])
324 039e3e61 Christos Stavrakakis
325 039e3e61 Christos Stavrakakis
    @assert_backend_closed
326 039e3e61 Christos Stavrakakis
    def test_get_metadata(self, backend):
327 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
328 dc99330c Georgios D. Tsoukalas
        response = self.myget('images/42/metadata/foo', 'user')
329 039e3e61 Christos Stavrakakis
        self.assertSuccess(response)
330 039e3e61 Christos Stavrakakis
        meta = json.loads(response.content)['meta']
331 039e3e61 Christos Stavrakakis
        self.assertEqual(meta['foo'], 'bar')
332 039e3e61 Christos Stavrakakis
333 039e3e61 Christos Stavrakakis
    @assert_backend_closed
334 039e3e61 Christos Stavrakakis
    def test_get_invalid_metadata(self, backend):
335 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
336 dc99330c Georgios D. Tsoukalas
        response = self.myget('images/42/metadata/not_found', 'user')
337 039e3e61 Christos Stavrakakis
        self.assertItemNotFound(response)
338 039e3e61 Christos Stavrakakis
339 039e3e61 Christos Stavrakakis
    def test_delete_metadata_item(self, backend):
340 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
341 dc99330c Georgios D. Tsoukalas
        response = self.mydelete('images/42/metadata/foo', 'user')
342 b3fd98ae Christos Stavrakakis
        self.assertEqual(response.status_code, 204)
343 d984eedc Christos Stavrakakis
        backend.return_value.update_metadata\
344 d984eedc Christos Stavrakakis
               .assert_called_once_with('42', {'properties': {'foo2': 'bar2'}})
345 039e3e61 Christos Stavrakakis
346 039e3e61 Christos Stavrakakis
    @assert_backend_closed
347 039e3e61 Christos Stavrakakis
    def test_create_metadata_item(self, backend):
348 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
349 b3fd98ae Christos Stavrakakis
        request = {'meta': {'foo3': 'bar3'}}
350 dc99330c Georgios D. Tsoukalas
        response = self.myput('images/42/metadata/foo3', 'user',
351 dc99330c Georgios D. Tsoukalas
                              json.dumps(request), 'json')
352 b3fd98ae Christos Stavrakakis
        self.assertEqual(response.status_code, 201)
353 14c94c48 Christos Stavrakakis
        backend.return_value.update_metadata.assert_called_once_with('42',
354 b3fd98ae Christos Stavrakakis
                {'properties':
355 b3fd98ae Christos Stavrakakis
                    {'foo': 'bar', 'foo2': 'bar2', 'foo3': 'bar3'}})
356 039e3e61 Christos Stavrakakis
357 039e3e61 Christos Stavrakakis
    @assert_backend_closed
358 039e3e61 Christos Stavrakakis
    def test_create_metadata_malformed_1(self, backend):
359 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
360 b3fd98ae Christos Stavrakakis
        request = {'met': {'foo3': 'bar3'}}
361 dc99330c Georgios D. Tsoukalas
        response = self.myput('images/42/metadata/foo3', 'user',
362 dc99330c Georgios D. Tsoukalas
                              json.dumps(request), 'json')
363 b3fd98ae Christos Stavrakakis
        self.assertBadRequest(response)
364 039e3e61 Christos Stavrakakis
365 039e3e61 Christos Stavrakakis
    @assert_backend_closed
366 039e3e61 Christos Stavrakakis
    def test_create_metadata_malformed_2(self, backend):
367 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
368 2d04422f Christos Stavrakakis
        request = {'metadata': [('foo3', 'bar3')]}
369 dc99330c Georgios D. Tsoukalas
        response = self.myput('images/42/metadata/foo3', 'user',
370 dc99330c Georgios D. Tsoukalas
                              json.dumps(request), 'json')
371 b3fd98ae Christos Stavrakakis
        self.assertBadRequest(response)
372 039e3e61 Christos Stavrakakis
373 039e3e61 Christos Stavrakakis
    @assert_backend_closed
374 039e3e61 Christos Stavrakakis
    def test_create_metadata_malformed_3(self, backend):
375 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
376 b3fd98ae Christos Stavrakakis
        request = {'met': {'foo3': 'bar3', 'foo4': 'bar4'}}
377 dc99330c Georgios D. Tsoukalas
        response = self.myput('images/42/metadata/foo3', 'user',
378 d984eedc Christos Stavrakakis
                              json.dumps(request), 'json')
379 b3fd98ae Christos Stavrakakis
        self.assertBadRequest(response)
380 039e3e61 Christos Stavrakakis
381 039e3e61 Christos Stavrakakis
    @assert_backend_closed
382 039e3e61 Christos Stavrakakis
    def test_create_metadata_malformed_4(self, backend):
383 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
384 b3fd98ae Christos Stavrakakis
        request = {'met': {'foo3': 'bar3'}}
385 dc99330c Georgios D. Tsoukalas
        response = self.myput('images/42/metadata/foo4', 'user',
386 dc99330c Georgios D. Tsoukalas
                              json.dumps(request), 'json')
387 b3fd98ae Christos Stavrakakis
        self.assertBadRequest(response)
388 039e3e61 Christos Stavrakakis
389 039e3e61 Christos Stavrakakis
    @assert_backend_closed
390 039e3e61 Christos Stavrakakis
    def test_update_metadata_item(self, backend):
391 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
392 b3fd98ae Christos Stavrakakis
        request = {'metadata': {'foo': 'bar_new', 'foo4': 'bar4'}}
393 dc99330c Georgios D. Tsoukalas
        response = self.mypost('images/42/metadata', 'user',
394 dc99330c Georgios D. Tsoukalas
                               json.dumps(request), 'json')
395 b3fd98ae Christos Stavrakakis
        self.assertEqual(response.status_code, 201)
396 14c94c48 Christos Stavrakakis
        backend.return_value.update_metadata.assert_called_once_with('42',
397 b3fd98ae Christos Stavrakakis
                {'properties':
398 b3fd98ae Christos Stavrakakis
                    {'foo': 'bar_new', 'foo2': 'bar2', 'foo4': 'bar4'}
399 b3fd98ae Christos Stavrakakis
                })
400 039e3e61 Christos Stavrakakis
401 039e3e61 Christos Stavrakakis
    @assert_backend_closed
402 039e3e61 Christos Stavrakakis
    def test_update_metadata_malformed(self, backend):
403 039e3e61 Christos Stavrakakis
        backend.return_value.get_image.return_value = self.image
404 b3fd98ae Christos Stavrakakis
        request = {'meta': {'foo': 'bar_new', 'foo4': 'bar4'}}
405 dc99330c Georgios D. Tsoukalas
        response = self.mypost('images/42/metadata', 'user',
406 dc99330c Georgios D. Tsoukalas
                               json.dumps(request), 'json')
407 b3fd98ae Christos Stavrakakis
        self.assertBadRequest(response)