Statistics
| Branch: | Tag: | Revision:

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

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 mock import patch
37
from functools import wraps
38
from copy import deepcopy
39
from snf_django.utils.testing import BaseAPITest
40

    
41

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

    
58

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

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

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

    
119

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

    
129

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

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

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

    
177
    @assert_backend_closed
178
    def test_list_images_filters_error_1(self, backend):
179
        response = self.get("/plankton/images/?size_max=")
180
        self.assertBadRequest(response)
181

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

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

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

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

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

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

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