Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (9.7 kB)

1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
import json
35

    
36
from django.test import TestCase
37

    
38
from contextlib import contextmanager
39
from mock import patch
40
from functools import wraps
41
from copy import deepcopy
42
from snf_django.utils.testing import astakos_user, BaseAPITest
43

    
44

    
45
FILTERS = ('name', 'container_format', 'disk_format', 'status', 'size_min',
46
           'size_max')
47
PARAMS = ('sort_key', 'sort_dir')
48
SORT_KEY_OPTIONS = ('id', 'name', 'status', 'size', 'disk_format',
49
                    'container_format', 'created_at', 'updated_at')
50
SORT_DIR_OPTIONS = ('asc', 'desc')
51
LIST_FIELDS = ('status', 'name', 'disk_format', 'container_format', 'size',
52
               'id')
53
DETAIL_FIELDS = ('name', 'disk_format', 'container_format', 'size', 'checksum',
54
                 'location', 'created_at', 'updated_at', 'deleted_at',
55
                 'status', 'is_public', 'owner', 'properties', 'id')
56
ADD_FIELDS = ('name', 'id', 'store', 'disk_format', 'container_format', 'size',
57
              'checksum', 'is_public', 'owner', 'properties', 'location')
58
UPDATE_FIELDS = ('name', 'disk_format', 'container_format', 'is_public',
59
                 'owner', 'properties', 'status')
60

    
61

    
62
DummyImages = {
63
 '0786a349-9725-48ec-8b86-8598eefc4043':
64
 {'checksum': u'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
65
  u'container_format': u'bare',
66
  'created_at': '2012-12-04 09:50:20',
67
  'deleted_at': '',
68
  u'disk_format': u'diskdump',
69
  'id': u'0786a349-9725-48ec-8b86-8598eefc4043',
70
  'is_public': True,
71
  'location': u'pithos://foo@example.com/container/foo3',
72
  u'name': u'dummyname',
73
  'owner': u'foo@example.com',
74
  'properties': {},
75
  'size': 500L,
76
  u'status': u'available',
77
  'store': 'pithos',
78
  'updated_at': '2012-12-04 09:50:54'},
79

    
80
 'd8aa85b8-410b-4550-953d-6797572534e6':
81
 {'checksum': u'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
82
  u'container_format': u'bare',
83
  'created_at': '2012-11-26 11:56:42',
84
  'deleted_at': '',
85
  u'disk_format': u'diskdump',
86
  'id': u'd8aa85b8-410b-4550-953d-6797572534e6',
87
  'is_public': False,
88
  'location': u'pithos://foo@example.com/container/private',
89
  u'name': u'dummyname2',
90
  'owner': u'foo@example.com',
91
  'properties': {},
92
  'size': 10000L,
93
  u'status': u'available',
94
  'store': 'pithos',
95
  'updated_at': '2012-11-26 11:57:09'},
96

    
97
 '264fb9ac-2458-421c-b460-6a765a92825c':
98
 {'checksum': u'0c6d0586744781218672fff2d7ed94cc32efb02a6a8eb589a0628f0e22bd5a7f',
99
  u'container_format': u'bare',
100
  'created_at': '2012-11-26 11:52:54',
101
  'deleted_at': '',
102
  u'disk_format': u'diskdump',
103
  'id': u'264fb9ac-2458-421c-b460-6a765a92825c',
104
  'is_public': True,
105
  'location': u'pithos://foo@example.com/container/baz.diskdump',
106
  u'name': u'"dummyname3"',
107
  'owner': u'foo@example.com',
108
  'properties': {u'description': u'Debian Squeeze Base System',
109
                 u'gui': u'No GUI',
110
                 u'kernel': u'2.6.32',
111
                 u'os': u'debian',
112
                 u'osfamily': u'linux',
113
                 u'root_partition': u'1',
114
                 u'size': u'451',
115
                 u'sortorder': u'1',
116
                 u'users': u'root'},
117
  'size': 473772032L,
118
  u'status': u'available',
119
  'store': 'pithos',
120
  'updated_at': '2012-11-26 11:55:40'}}
121

    
122

    
123
def assert_backend_closed(func):
124
    @wraps(func)
125
    def wrapper(self, backend):
126
        result = func(self, backend)
127
        if backend.called is True:
128
            backend.return_value.close.assert_called_once_with()
129
        return result
130
    return wrapper
131

    
132

    
133
@patch("synnefo.plankton.utils.ImageBackend")
134
class PlanktonTest(BaseAPITest):
135
    @assert_backend_closed
136
    def test_list_images(self, backend):
137
        backend.return_value.list.return_value =\
138
                deepcopy(DummyImages).values()
139
        response = self.get("/plankton/images/")
140
        self.assertSuccess(response)
141
        images = json.loads(response.content)
142
        for api_image in images:
143
            id = api_image['id']
144
            pithos_image = dict([(key, val)\
145
                                for key, val in DummyImages[id].items()\
146
                                if key in LIST_FIELDS])
147
            self.assertEqual(api_image, pithos_image)
148
        backend.return_value\
149
                .list.assert_called_once_with({}, {'sort_key': 'created_at',
150
                                                   'sort_dir': 'desc'})
151

    
152
    @assert_backend_closed
153
    def test_list_images_detail(self, backend):
154
        backend.return_value.list.return_value =\
155
                deepcopy(DummyImages).values()
156
        response = self.get("/plankton/images/detail")
157
        self.assertSuccess(response)
158
        images = json.loads(response.content)
159
        for api_image in images:
160
            id = api_image['id']
161
            pithos_image = dict([(key, val)\
162
                                for key, val in DummyImages[id].items()\
163
                                if key in DETAIL_FIELDS])
164
            self.assertEqual(api_image, pithos_image)
165
        backend.return_value\
166
                .list.assert_called_once_with({}, {'sort_key': 'created_at',
167
                                                   'sort_dir': 'desc'})
168

    
169
    @assert_backend_closed
170
    def test_list_images_filters(self, backend):
171
        backend.return_value.list.return_value =\
172
                deepcopy(DummyImages).values()
173
        response = self.get("/plankton/images/?size_max=1000")
174
        self.assertSuccess(response)
175
        backend.return_value\
176
                .list.assert_called_once_with({'size_max': 1000},
177
                                              {'sort_key': 'created_at',
178
                                               'sort_dir': 'desc'})
179

    
180
    @assert_backend_closed
181
    def test_list_images_filters_error_1(self, backend):
182
        response = self.get("/plankton/images/?size_max=")
183
        self.assertBadRequest(response)
184

    
185
    @assert_backend_closed
186
    def test_list_images_filters_error_2(self, backend):
187
        response = self.get("/plankton/images/?size_min=foo")
188
        self.assertBadRequest(response)
189

    
190
    @assert_backend_closed
191
    def test_update_image(self, backend):
192
        db_image = DummyImages.values()[0]
193
        response = self.put("/plankton/images/%s" % db_image['id'],
194
                            json.dumps({}),
195
                            'json', HTTP_X_IMAGE_META_OWNER='user2')
196
        self.assertSuccess(response)
197
        backend.return_value.update.assert_called_once_with(db_image['id'],
198
                                                            {"owner": "user2"})
199

    
200
    @assert_backend_closed
201
    def test_add_image_member(self, backend):
202
        image_id = DummyImages.values()[0]['id']
203
        response = self.put("/plankton/images/%s/members/user3" % image_id,
204
                            json.dumps({}), 'json')
205
        self.assertSuccess(response)
206
        backend.return_value.add_user.assert_called_once_with(image_id,
207
                                                             'user3')
208

    
209
    @assert_backend_closed
210
    def test_remove_image_member(self, backend):
211
        image_id = DummyImages.values()[0]['id']
212
        response = self.delete("/plankton/images/%s/members/user3" % image_id)
213
        self.assertSuccess(response)
214
        backend.return_value.remove_user.assert_called_once_with(image_id,
215
                                                                'user3')
216

    
217
    @assert_backend_closed
218
    def test_add_image(self, backend):
219
        response = self.post("/plankton/images/",
220
                             json.dumps({}),
221
                             'json',
222
                             HTTP_X_IMAGE_META_NAME='dummy_name',
223
                             HTTP_X_IMAGE_META_OWNER='dummy_owner',
224
                             HTTP_X_IMAGE_META_LOCATION='dummy_location')
225
        self.assertSuccess(response)
226
        backend.return_value.register.assert_called_once_with('dummy_name',
227
                                                              'dummy_location',
228
                                                      {'owner': 'dummy_owner'})
229

    
230
    @assert_backend_closed
231
    def test_get_image(self, backend):
232
        response = self.get("/plankton/images/123")
233
        self.assertEqual(response.status_code, 501)
234

    
235
    @assert_backend_closed
236
    def test_delete_image(self, backend):
237
        response = self.delete("/plankton/images/123")
238
        self.assertEqual(response.status_code, 204)
239
        backend.return_value.unregister.assert_called_once_with('123')
240
        backend.return_value._delete.assert_not_called()