1 # Copyright 2012-2013 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
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.
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.
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.
34 from mock import patch
37 from unittest import TestCase
38 from kamaki.clients import ClientError
42 "status": "available",
44 "disk_format": "diskdump",
45 "container_format": "bare",
46 "id": "b4713f20-3a41-4eaf-81ae-88698c18b3e8",
49 "status": "available",
50 "name": "Debian_Wheezy_Base",
51 "disk_format": "diskdump",
52 "container_format": "bare",
53 "id": "1f8454f0-8e3e-4b6c-ab8e-5236b728dffe",
56 "status": "available",
58 "disk_format": "diskdump",
59 "container_format": "bare",
60 "id": "0fb03e45-7d5a-4515-bd4e-e6bbf6457f06",
63 "status": "available",
65 "disk_format": "diskdump",
66 "container_format": "bare",
67 "id": "5963020b-ab74-4e11-bc59-90c494bbdedb",
70 example_images_detailed = [
72 "status": "available",
74 "checksum": "1a126aad07475b43cc1959b446344211be13974",
75 "created_at": "2013-01-28 22:44:54",
76 "disk_format": "diskdump",
77 "updated_at": "2013-01-28 22:44:55",
79 "partition_table": "msdos",
82 "exclude_task_assignhostname": "yes",
84 "root_partition": "1",
85 "description": "Archlinux base install 2012.12.01"},
86 "location": "pithos://us3r-I6E-1d/images/archlinux.12.2012",
87 "container_format": "bare",
88 "owner": "user163@mail.example.com",
91 "id": "b4713f20-3a41-4eaf-81ae-88698c18b3e8",
94 "status": "available",
95 "name": "Debian_Wheezy_Base",
96 "checksum": "8f96e73ba8886a05de6f9b3705c981",
97 "created_at": "2013-01-29 16:41:13",
98 "disk_format": "diskdump",
99 "updated_at": "2013-01-29 16:41:14",
101 "partition_table": "msdos",
106 "root_partition": "1",
107 "description": "Debian7.0(Wheezy)Base"},
108 "location": "pithos://us3r-EO2-1d/images/Deb_Whz201301291840.diskdump",
109 "container_format": "bare",
110 "owner": "user302@mail.example.com",
113 "id": "1f8454f0-8e3e-4b6c-ab8e-5236b728dffe",
116 "status": "available",
118 "checksum": "b202b8c7030cb22f896c6664ac",
119 "created_at": "2013-02-13 10:07:42",
120 "disk_format": "diskdump",
121 "updated_at": "2013-02-13 10:07:44",
123 "partition_table": "msdos",
125 "description": "Ubuntu 12.04.1 LTS",
127 "root_partition": "1",
129 "location": "pithos://us3r-@r3n@-1d/images/mls-201302131203.diskdump",
130 "container_format": "bare",
131 "owner": "user3@mail.example.com",
134 "id": "0fb03e45-7d5a-4515-bd4e-e6bbf6457f06",
137 "status": "available",
139 "checksum": "06d3099815d1f6fada91e80107638b882",
140 "created_at": "2013-02-13 12:35:21",
141 "disk_format": "diskdump",
142 "updated_at": "2013-02-13 12:35:23",
144 "partition_table": "msdos",
146 "description": "Ubuntu 12.04.2 LTS",
148 "root_partition": "1",
150 "location": "pithos://us3r-E-1d/images/Gardenia-201302131431.diskdump",
151 "container_format": "bare",
152 "owner": "user3@mail.example.com",
155 "id": "5963020b-ab74-4e11-bc59-90c494bbdedb",
159 class Image(TestCase):
162 json = example_images
172 self.now = time.mktime(time.gmtime())
173 self.imgname = 'img_%s' % self.now
174 self.url = 'http://image.example.com'
175 self.token = 'an1m@g370k3n=='
176 from kamaki.clients.image import ImageClient
177 self.client = ImageClient(self.url, self.token)
178 self.cyclades_url = 'http://cyclades.example.com'
179 from kamaki.clients.cyclades import CycladesClient
180 self.cyclades = CycladesClient(self.cyclades_url, self.token)
181 from kamaki.clients.connection.kamakicon import KamakiHTTPConnection
182 self.C = KamakiHTTPConnection
185 self.FR.json = example_images
187 def assert_dicts_are_deeply_equal(self, d1, d2):
188 for k, v in d1.items():
189 self.assertTrue(k in d2)
190 if isinstance(v, dict):
191 self.assert_dicts_are_deeply_equal(v, d2[k])
193 self.assertEqual(unicode(v), unicode(d2[k]))
195 def test_list_public(self):
199 return_value=self.FR()) as perform_req:
200 r = self.client.list_public()
201 self.assertEqual(self.client.http_client.url, self.url)
202 self.assertEqual(self.client.http_client.path, '/images/')
203 params = perform_req.call_args[0][3]
204 self.assertEqual(params['sort_dir'], 'asc')
205 for i in range(len(r)):
206 self.assert_dicts_are_deeply_equal(r[i], example_images[i])
208 r = self.client.list_public(order='-')
209 params = perform_req.call_args[0][3]
210 self.assertEqual(params['sort_dir'], 'desc')
211 self.assertEqual(self.client.http_client.url, self.url)
212 self.assertEqual(self.client.http_client.path, '/images/')
214 self.FR.json = example_images_detailed
215 r = self.client.list_public(detail=True)
216 self.assertEqual(self.client.http_client.url, self.url)
217 self.assertEqual(self.client.http_client.path, '/images/detail')
218 for i in range(len(r)):
219 self.assert_dicts_are_deeply_equal(
221 example_images_detailed[i])
223 size_max = 1000000000
224 r = self.client.list_public(filters=dict(size_max=size_max))
225 params = perform_req.call_args[0][3]
226 self.assertEqual(params['size_max'], size_max)
227 self.assertEqual(self.client.http_client.url, self.url)
228 self.assertEqual(self.client.http_client.path, '/images/')
230 def test_get_meta(self):
231 img0 = example_images[0]
234 for k, v in example_images_detailed[0].items():
235 img0_headers['x-image-meta-%s' % k] = v
236 self.FR.headers = img0_headers
237 with patch.object(self.C, 'perform_request', return_value=self.FR()):
238 r = self.client.get_meta(img0['id'])
239 self.assertEqual(self.client.http_client.url, self.url)
240 expected_path = '/images/%s' % img0['id']
241 self.assertEqual(self.client.http_client.path, expected_path)
243 self.assertEqual(r['id'], img0['id'])
244 self.assert_dicts_are_deeply_equal(r, example_images_detailed[0])
246 def test_register(self):
247 img0 = example_images_detailed[0]
248 img0_location = img0['location']
249 img0_name = 'A new img0 name'
253 return_value=self.FR()) as perform_req:
254 self.client.register(img0_name, img0_location)
255 self.assertEqual(self.client.http_client.url, self.url)
256 self.assertEqual(self.client.http_client.path, '/images/')
257 (method, data, headers, params) = perform_req.call_args[0]
258 self.assertEqual(method, 'post')
259 self.assertTrue(0 == len(params))
261 val = 'Some random value'
266 container_format=val,
271 for key in param_dict.keys():
273 self.client.register(img0_name, img0_location, params=param)
274 (method, data, a_headers, a_params) = perform_req.call_args[0]
275 key = 'x-image-meta-%s' % key.replace('_', '-')
276 self.assertEqual(a_headers[key], val)
277 self.client.register(img0_name, img0_location, params=param_dict)
278 (method, data, a_headers, a_params) = perform_req.call_args[0]
279 self.assertEqual(len(param_dict), len(a_headers))
280 for key, val in param_dict.items():
281 key = 'x-image-meta-%s' % key.replace('_', '-')
282 self.assertEqual(a_headers[key], val)
284 props = dict(key0='val0', key2='val2', key3='val3')
285 self.client.register(img0_name, img0_location, properties=props)
286 (method, data, a_headers, a_params) = perform_req.call_args[0]
287 for k, v in props.items():
288 self.assertEquals(a_headers['X-Image-Meta-Property-%s' % k], v)
291 def test_set_members(self):
294 self._test_set_members()
296 def _test_set_members(self):
297 members = ['%s@fake.net' % self.now]
298 for img in self._imglist.values():
299 self.client.set_members(img['id'], members)
300 r = self.client.list_members(img['id'])
301 self.assertEqual(r[0]['member_id'], members[0])
303 def test_list_members(self):
304 ""Test list_members""
305 self._test_list_members()
307 def _test_list_members(self):
308 self._test_set_members()
310 def test_remove_members(self):
311 ""Test remove_members - NO CHECK""
313 self._test_remove_members()
315 def _test_remove_members(self):
317 members = ['%s@fake.net' % self.now, '%s_v2@fake.net' % self.now]
318 for img in self._imglist.values():
319 self.client.set_members(img['id'], members)
320 r = self.client.list_members(img['id'])
321 self.assertTrue(len(r) > 1)
322 self.client.remove_member(img['id'], members[0])
323 r0 = self.client.list_members(img['id'])
324 self.assertEqual(len(r), 1 + len(r0))
325 self.assertEqual(r0[0]['member_id'], members[1])
327 def test_list_shared(self):
328 ""Test list_shared - NOT CHECKED""
329 self._test_list_shared()
331 def _test_list_shared(self):
332 #No way to test this, if I dont have member images