Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / plankton / tests.py @ 4a769fc0

History | View | Annotate | Download (10.9 kB)

1 37f87d98 Christos Stavrakakis
# Copyright 2012 GRNET S.A. All rights reserved.
2 37f87d98 Christos Stavrakakis
#
3 37f87d98 Christos Stavrakakis
# Redistribution and use in source and binary forms, with or
4 37f87d98 Christos Stavrakakis
# without modification, are permitted provided that the following
5 37f87d98 Christos Stavrakakis
# conditions are met:
6 37f87d98 Christos Stavrakakis
#
7 37f87d98 Christos Stavrakakis
#   1. Redistributions of source code must retain the above
8 37f87d98 Christos Stavrakakis
#      copyright notice, this list of conditions and the following
9 37f87d98 Christos Stavrakakis
#      disclaimer.
10 37f87d98 Christos Stavrakakis
#
11 37f87d98 Christos Stavrakakis
#   2. Redistributions in binary form must reproduce the above
12 37f87d98 Christos Stavrakakis
#      copyright notice, this list of conditions and the following
13 37f87d98 Christos Stavrakakis
#      disclaimer in the documentation and/or other materials
14 37f87d98 Christos Stavrakakis
#      provided with the distribution.
15 37f87d98 Christos Stavrakakis
#
16 37f87d98 Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 37f87d98 Christos Stavrakakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 37f87d98 Christos Stavrakakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 37f87d98 Christos Stavrakakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 37f87d98 Christos Stavrakakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 37f87d98 Christos Stavrakakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 37f87d98 Christos Stavrakakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 37f87d98 Christos Stavrakakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 37f87d98 Christos Stavrakakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 37f87d98 Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 37f87d98 Christos Stavrakakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 37f87d98 Christos Stavrakakis
# POSSIBILITY OF SUCH DAMAGE.
28 37f87d98 Christos Stavrakakis
#
29 37f87d98 Christos Stavrakakis
# The views and conclusions contained in the software and
30 37f87d98 Christos Stavrakakis
# documentation are those of the authors and should not be
31 37f87d98 Christos Stavrakakis
# interpreted as representing official policies, either expressed
32 37f87d98 Christos Stavrakakis
# or implied, of GRNET S.A.
33 37f87d98 Christos Stavrakakis
34 37f87d98 Christos Stavrakakis
import json
35 37f87d98 Christos Stavrakakis
36 37f87d98 Christos Stavrakakis
from mock import patch
37 37f87d98 Christos Stavrakakis
from functools import wraps
38 37f87d98 Christos Stavrakakis
from copy import deepcopy
39 cda71050 Christos Stavrakakis
from snf_django.utils.testing import BaseAPITest
40 fdb15edb Georgios D. Tsoukalas
from synnefo.cyclades_settings import cyclades_services
41 fdb15edb Georgios D. Tsoukalas
from synnefo.lib.services import get_service_path
42 fdb15edb Georgios D. Tsoukalas
from synnefo.lib import join_urls
43 fdb15edb Georgios D. Tsoukalas
44 fdb15edb Georgios D. Tsoukalas
45 fdb15edb Georgios D. Tsoukalas
class PlanktonAPITest(BaseAPITest):
46 fdb15edb Georgios D. Tsoukalas
    def setUp(self, *args, **kwargs):
47 fdb15edb Georgios D. Tsoukalas
        super(PlanktonAPITest, self).setUp(*args, **kwargs)
48 66855d86 Georgios D. Tsoukalas
        self.api_path = get_service_path(cyclades_services, 'image',
49 fdb15edb Georgios D. Tsoukalas
                                             version='v1.0')
50 fdb15edb Georgios D. Tsoukalas
    def myget(self, path, *args, **kwargs):
51 66855d86 Georgios D. Tsoukalas
        path = join_urls(self.api_path, path)
52 fdb15edb Georgios D. Tsoukalas
        return self.get(path, *args, **kwargs)
53 fdb15edb Georgios D. Tsoukalas
54 fdb15edb Georgios D. Tsoukalas
    def myput(self, path, *args, **kwargs):
55 66855d86 Georgios D. Tsoukalas
        path = join_urls(self.api_path, path)
56 fdb15edb Georgios D. Tsoukalas
        return self.put(path, *args, **kwargs)
57 fdb15edb Georgios D. Tsoukalas
58 fdb15edb Georgios D. Tsoukalas
    def mypost(self, path, *args, **kwargs):
59 66855d86 Georgios D. Tsoukalas
        path = join_urls(self.api_path, path)
60 fdb15edb Georgios D. Tsoukalas
        return self.post(path, *args, **kwargs)
61 fdb15edb Georgios D. Tsoukalas
62 fdb15edb Georgios D. Tsoukalas
    def mydelete(self, path, *args, **kwargs):
63 66855d86 Georgios D. Tsoukalas
        path = join_urls(self.api_path, path)
64 fdb15edb Georgios D. Tsoukalas
        return self.delete(path, *args, **kwargs)
65 37f87d98 Christos Stavrakakis
66 37f87d98 Christos Stavrakakis
67 37f87d98 Christos Stavrakakis
FILTERS = ('name', 'container_format', 'disk_format', 'status', 'size_min',
68 37f87d98 Christos Stavrakakis
           'size_max')
69 37f87d98 Christos Stavrakakis
PARAMS = ('sort_key', 'sort_dir')
70 37f87d98 Christos Stavrakakis
SORT_KEY_OPTIONS = ('id', 'name', 'status', 'size', 'disk_format',
71 37f87d98 Christos Stavrakakis
                    'container_format', 'created_at', 'updated_at')
72 37f87d98 Christos Stavrakakis
SORT_DIR_OPTIONS = ('asc', 'desc')
73 37f87d98 Christos Stavrakakis
LIST_FIELDS = ('status', 'name', 'disk_format', 'container_format', 'size',
74 37f87d98 Christos Stavrakakis
               'id')
75 37f87d98 Christos Stavrakakis
DETAIL_FIELDS = ('name', 'disk_format', 'container_format', 'size', 'checksum',
76 37f87d98 Christos Stavrakakis
                 'location', 'created_at', 'updated_at', 'deleted_at',
77 37f87d98 Christos Stavrakakis
                 'status', 'is_public', 'owner', 'properties', 'id')
78 37f87d98 Christos Stavrakakis
ADD_FIELDS = ('name', 'id', 'store', 'disk_format', 'container_format', 'size',
79 37f87d98 Christos Stavrakakis
              'checksum', 'is_public', 'owner', 'properties', 'location')
80 37f87d98 Christos Stavrakakis
UPDATE_FIELDS = ('name', 'disk_format', 'container_format', 'is_public',
81 37f87d98 Christos Stavrakakis
                 'owner', 'properties', 'status')
82 37f87d98 Christos Stavrakakis
83 37f87d98 Christos Stavrakakis
84 37f87d98 Christos Stavrakakis
DummyImages = {
85 37f87d98 Christos Stavrakakis
 '0786a349-9725-48ec-8b86-8598eefc4043':
86 37f87d98 Christos Stavrakakis
 {'checksum': u'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
87 37f87d98 Christos Stavrakakis
  u'container_format': u'bare',
88 37f87d98 Christos Stavrakakis
  'created_at': '2012-12-04 09:50:20',
89 37f87d98 Christos Stavrakakis
  'deleted_at': '',
90 37f87d98 Christos Stavrakakis
  u'disk_format': u'diskdump',
91 37f87d98 Christos Stavrakakis
  'id': u'0786a349-9725-48ec-8b86-8598eefc4043',
92 37f87d98 Christos Stavrakakis
  'is_public': True,
93 37f87d98 Christos Stavrakakis
  'location': u'pithos://foo@example.com/container/foo3',
94 37f87d98 Christos Stavrakakis
  u'name': u'dummyname',
95 37f87d98 Christos Stavrakakis
  'owner': u'foo@example.com',
96 37f87d98 Christos Stavrakakis
  'properties': {},
97 37f87d98 Christos Stavrakakis
  'size': 500L,
98 37f87d98 Christos Stavrakakis
  u'status': u'available',
99 37f87d98 Christos Stavrakakis
  'store': 'pithos',
100 37f87d98 Christos Stavrakakis
  'updated_at': '2012-12-04 09:50:54'},
101 37f87d98 Christos Stavrakakis
102 37f87d98 Christos Stavrakakis
 'd8aa85b8-410b-4550-953d-6797572534e6':
103 37f87d98 Christos Stavrakakis
 {'checksum': u'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
104 37f87d98 Christos Stavrakakis
  u'container_format': u'bare',
105 37f87d98 Christos Stavrakakis
  'created_at': '2012-11-26 11:56:42',
106 37f87d98 Christos Stavrakakis
  'deleted_at': '',
107 37f87d98 Christos Stavrakakis
  u'disk_format': u'diskdump',
108 37f87d98 Christos Stavrakakis
  'id': u'd8aa85b8-410b-4550-953d-6797572534e6',
109 37f87d98 Christos Stavrakakis
  'is_public': False,
110 37f87d98 Christos Stavrakakis
  'location': u'pithos://foo@example.com/container/private',
111 37f87d98 Christos Stavrakakis
  u'name': u'dummyname2',
112 37f87d98 Christos Stavrakakis
  'owner': u'foo@example.com',
113 37f87d98 Christos Stavrakakis
  'properties': {},
114 37f87d98 Christos Stavrakakis
  'size': 10000L,
115 37f87d98 Christos Stavrakakis
  u'status': u'available',
116 37f87d98 Christos Stavrakakis
  'store': 'pithos',
117 37f87d98 Christos Stavrakakis
  'updated_at': '2012-11-26 11:57:09'},
118 37f87d98 Christos Stavrakakis
119 37f87d98 Christos Stavrakakis
 '264fb9ac-2458-421c-b460-6a765a92825c':
120 37f87d98 Christos Stavrakakis
 {'checksum': u'0c6d0586744781218672fff2d7ed94cc32efb02a6a8eb589a0628f0e22bd5a7f',
121 37f87d98 Christos Stavrakakis
  u'container_format': u'bare',
122 37f87d98 Christos Stavrakakis
  'created_at': '2012-11-26 11:52:54',
123 37f87d98 Christos Stavrakakis
  'deleted_at': '',
124 37f87d98 Christos Stavrakakis
  u'disk_format': u'diskdump',
125 37f87d98 Christos Stavrakakis
  'id': u'264fb9ac-2458-421c-b460-6a765a92825c',
126 37f87d98 Christos Stavrakakis
  'is_public': True,
127 37f87d98 Christos Stavrakakis
  'location': u'pithos://foo@example.com/container/baz.diskdump',
128 37f87d98 Christos Stavrakakis
  u'name': u'"dummyname3"',
129 37f87d98 Christos Stavrakakis
  'owner': u'foo@example.com',
130 37f87d98 Christos Stavrakakis
  'properties': {u'description': u'Debian Squeeze Base System',
131 37f87d98 Christos Stavrakakis
                 u'gui': u'No GUI',
132 37f87d98 Christos Stavrakakis
                 u'kernel': u'2.6.32',
133 37f87d98 Christos Stavrakakis
                 u'os': u'debian',
134 37f87d98 Christos Stavrakakis
                 u'osfamily': u'linux',
135 37f87d98 Christos Stavrakakis
                 u'root_partition': u'1',
136 37f87d98 Christos Stavrakakis
                 u'size': u'451',
137 37f87d98 Christos Stavrakakis
                 u'sortorder': u'1',
138 37f87d98 Christos Stavrakakis
                 u'users': u'root'},
139 37f87d98 Christos Stavrakakis
  'size': 473772032L,
140 37f87d98 Christos Stavrakakis
  u'status': u'available',
141 37f87d98 Christos Stavrakakis
  'store': 'pithos',
142 37f87d98 Christos Stavrakakis
  'updated_at': '2012-11-26 11:55:40'}}
143 37f87d98 Christos Stavrakakis
144 37f87d98 Christos Stavrakakis
145 37f87d98 Christos Stavrakakis
def assert_backend_closed(func):
146 37f87d98 Christos Stavrakakis
    @wraps(func)
147 37f87d98 Christos Stavrakakis
    def wrapper(self, backend):
148 37f87d98 Christos Stavrakakis
        result = func(self, backend)
149 37f87d98 Christos Stavrakakis
        if backend.called is True:
150 37f87d98 Christos Stavrakakis
            backend.return_value.close.assert_called_once_with()
151 37f87d98 Christos Stavrakakis
        return result
152 37f87d98 Christos Stavrakakis
    return wrapper
153 37f87d98 Christos Stavrakakis
154 37f87d98 Christos Stavrakakis
155 cda71050 Christos Stavrakakis
@patch("synnefo.plankton.backend.ImageBackend")
156 fdb15edb Georgios D. Tsoukalas
class PlanktonTest(PlanktonAPITest):
157 37f87d98 Christos Stavrakakis
    @assert_backend_closed
158 37f87d98 Christos Stavrakakis
    def test_list_images(self, backend):
159 14c94c48 Christos Stavrakakis
        backend.return_value.list_images.return_value =\
160 37f87d98 Christos Stavrakakis
                deepcopy(DummyImages).values()
161 fdb15edb Georgios D. Tsoukalas
        response = self.myget("images/")
162 37f87d98 Christos Stavrakakis
        self.assertSuccess(response)
163 37f87d98 Christos Stavrakakis
        images = json.loads(response.content)
164 37f87d98 Christos Stavrakakis
        for api_image in images:
165 37f87d98 Christos Stavrakakis
            id = api_image['id']
166 37f87d98 Christos Stavrakakis
            pithos_image = dict([(key, val)\
167 37f87d98 Christos Stavrakakis
                                for key, val in DummyImages[id].items()\
168 37f87d98 Christos Stavrakakis
                                if key in LIST_FIELDS])
169 37f87d98 Christos Stavrakakis
            self.assertEqual(api_image, pithos_image)
170 37f87d98 Christos Stavrakakis
        backend.return_value\
171 14c94c48 Christos Stavrakakis
                .list_images.assert_called_once_with({}, {'sort_key': 'created_at',
172 37f87d98 Christos Stavrakakis
                                                   'sort_dir': 'desc'})
173 37f87d98 Christos Stavrakakis
174 37f87d98 Christos Stavrakakis
    @assert_backend_closed
175 37f87d98 Christos Stavrakakis
    def test_list_images_detail(self, backend):
176 14c94c48 Christos Stavrakakis
        backend.return_value.list_images.return_value =\
177 37f87d98 Christos Stavrakakis
                deepcopy(DummyImages).values()
178 fdb15edb Georgios D. Tsoukalas
        response = self.myget("images/detail")
179 37f87d98 Christos Stavrakakis
        self.assertSuccess(response)
180 37f87d98 Christos Stavrakakis
        images = json.loads(response.content)
181 37f87d98 Christos Stavrakakis
        for api_image in images:
182 37f87d98 Christos Stavrakakis
            id = api_image['id']
183 37f87d98 Christos Stavrakakis
            pithos_image = dict([(key, val)\
184 37f87d98 Christos Stavrakakis
                                for key, val in DummyImages[id].items()\
185 37f87d98 Christos Stavrakakis
                                if key in DETAIL_FIELDS])
186 37f87d98 Christos Stavrakakis
            self.assertEqual(api_image, pithos_image)
187 37f87d98 Christos Stavrakakis
        backend.return_value\
188 14c94c48 Christos Stavrakakis
                .list_images.assert_called_once_with({}, {'sort_key': 'created_at',
189 37f87d98 Christos Stavrakakis
                                                   'sort_dir': 'desc'})
190 37f87d98 Christos Stavrakakis
191 37f87d98 Christos Stavrakakis
    @assert_backend_closed
192 37f87d98 Christos Stavrakakis
    def test_list_images_filters(self, backend):
193 14c94c48 Christos Stavrakakis
        backend.return_value.list_images.return_value =\
194 37f87d98 Christos Stavrakakis
                deepcopy(DummyImages).values()
195 fdb15edb Georgios D. Tsoukalas
        response = self.myget("images/?size_max=1000")
196 37f87d98 Christos Stavrakakis
        self.assertSuccess(response)
197 37f87d98 Christos Stavrakakis
        backend.return_value\
198 14c94c48 Christos Stavrakakis
                .list_images.assert_called_once_with({'size_max': 1000},
199 14c94c48 Christos Stavrakakis
                                                     {'sort_key': 'created_at',
200 14c94c48 Christos Stavrakakis
                                                     'sort_dir': 'desc'})
201 37f87d98 Christos Stavrakakis
202 37f87d98 Christos Stavrakakis
    @assert_backend_closed
203 450a6d2b Christos Stavrakakis
    def test_list_images_filters_error_1(self, backend):
204 fdb15edb Georgios D. Tsoukalas
        response = self.myget("images/?size_max=")
205 450a6d2b Christos Stavrakakis
        self.assertBadRequest(response)
206 450a6d2b Christos Stavrakakis
207 450a6d2b Christos Stavrakakis
    @assert_backend_closed
208 450a6d2b Christos Stavrakakis
    def test_list_images_filters_error_2(self, backend):
209 fdb15edb Georgios D. Tsoukalas
        response = self.myget("images/?size_min=foo")
210 450a6d2b Christos Stavrakakis
        self.assertBadRequest(response)
211 450a6d2b Christos Stavrakakis
212 450a6d2b Christos Stavrakakis
    @assert_backend_closed
213 37f87d98 Christos Stavrakakis
    def test_update_image(self, backend):
214 37f87d98 Christos Stavrakakis
        db_image = DummyImages.values()[0]
215 fdb15edb Georgios D. Tsoukalas
        response = self.myput("images/%s" % db_image['id'],
216 fdb15edb Georgios D. Tsoukalas
                              json.dumps({}),
217 fdb15edb Georgios D. Tsoukalas
                              'json', HTTP_X_IMAGE_META_OWNER='user2')
218 37f87d98 Christos Stavrakakis
        self.assertSuccess(response)
219 14c94c48 Christos Stavrakakis
        backend.return_value.update_metadata.assert_called_once_with(db_image['id'],
220 14c94c48 Christos Stavrakakis
                                                                     {"owner": "user2"})
221 37f87d98 Christos Stavrakakis
222 37f87d98 Christos Stavrakakis
    @assert_backend_closed
223 37f87d98 Christos Stavrakakis
    def test_add_image_member(self, backend):
224 37f87d98 Christos Stavrakakis
        image_id = DummyImages.values()[0]['id']
225 fdb15edb Georgios D. Tsoukalas
        response = self.myput("images/%s/members/user3" % image_id,
226 fdb15edb Georgios D. Tsoukalas
                              json.dumps({}), 'json')
227 37f87d98 Christos Stavrakakis
        self.assertSuccess(response)
228 37f87d98 Christos Stavrakakis
        backend.return_value.add_user.assert_called_once_with(image_id,
229 37f87d98 Christos Stavrakakis
                                                             'user3')
230 37f87d98 Christos Stavrakakis
231 37f87d98 Christos Stavrakakis
    @assert_backend_closed
232 37f87d98 Christos Stavrakakis
    def test_remove_image_member(self, backend):
233 37f87d98 Christos Stavrakakis
        image_id = DummyImages.values()[0]['id']
234 fdb15edb Georgios D. Tsoukalas
        response = self.mydelete("images/%s/members/user3" % image_id)
235 37f87d98 Christos Stavrakakis
        self.assertSuccess(response)
236 37f87d98 Christos Stavrakakis
        backend.return_value.remove_user.assert_called_once_with(image_id,
237 37f87d98 Christos Stavrakakis
                                                                'user3')
238 37f87d98 Christos Stavrakakis
239 37f87d98 Christos Stavrakakis
    @assert_backend_closed
240 37f87d98 Christos Stavrakakis
    def test_add_image(self, backend):
241 59573532 Christos Stavrakakis
        location = "pithos://uuid/container/name/"
242 fdb15edb Georgios D. Tsoukalas
        response = self.mypost("images/",
243 fdb15edb Georgios D. Tsoukalas
                               json.dumps({}),
244 fdb15edb Georgios D. Tsoukalas
                               'json',
245 fdb15edb Georgios D. Tsoukalas
                               HTTP_X_IMAGE_META_NAME='dummy_name',
246 fdb15edb Georgios D. Tsoukalas
                               HTTP_X_IMAGE_META_OWNER='dummy_owner',
247 fdb15edb Georgios D. Tsoukalas
                               HTTP_X_IMAGE_META_LOCATION=location)
248 37f87d98 Christos Stavrakakis
        self.assertSuccess(response)
249 37f87d98 Christos Stavrakakis
        backend.return_value.register.assert_called_once_with('dummy_name',
250 59573532 Christos Stavrakakis
                                                              location,
251 52194c77 Christos Stavrakakis
                                                      {'owner': 'dummy_owner'})
252 37f87d98 Christos Stavrakakis
253 37f87d98 Christos Stavrakakis
    @assert_backend_closed
254 37f87d98 Christos Stavrakakis
    def test_get_image(self, backend):
255 fdb15edb Georgios D. Tsoukalas
        response = self.myget("images/123")
256 37f87d98 Christos Stavrakakis
        self.assertEqual(response.status_code, 501)
257 f13aab5d Christos Stavrakakis
258 f13aab5d Christos Stavrakakis
    @assert_backend_closed
259 f13aab5d Christos Stavrakakis
    def test_delete_image(self, backend):
260 fdb15edb Georgios D. Tsoukalas
        response = self.mydelete("images/123")
261 f13aab5d Christos Stavrakakis
        self.assertEqual(response.status_code, 204)
262 f13aab5d Christos Stavrakakis
        backend.return_value.unregister.assert_called_once_with('123')
263 f13aab5d Christos Stavrakakis
        backend.return_value._delete.assert_not_called()
264 f7d0a71c Georgios D. Tsoukalas
265 f7d0a71c Georgios D. Tsoukalas
    @assert_backend_closed
266 f7d0a71c Georgios D. Tsoukalas
    def test_catch_wrong_api_paths(self, *args):
267 f7d0a71c Georgios D. Tsoukalas
        response = self.myget('nonexistent')
268 f7d0a71c Georgios D. Tsoukalas
        self.assertEqual(response.status_code, 400)
269 f7d0a71c Georgios D. Tsoukalas
        try:
270 f7d0a71c Georgios D. Tsoukalas
            error = json.loads(response.content)
271 f7d0a71c Georgios D. Tsoukalas
        except ValueError:
272 f7d0a71c Georgios D. Tsoukalas
            self.assertTrue(False)