Revision 52194c77 snf-cyclades-app/synnefo/api/tests.py

b/snf-cyclades-app/synnefo/api/tests.py
35 35

  
36 36
from django.utils import simplejson as json
37 37
from django.test import TestCase
38
from django.test.client import Client
39

  
40
from synnefo.db.models import *
41
from synnefo.logic.utils import get_rsapi_state
42 38

  
43 39
from mock import patch, Mock
44

  
45 40
from contextlib import contextmanager
41
from functools import wraps
42

  
43
from synnefo.db.models import *
46 44
from synnefo.db import models_factory as mfactory
45
from synnefo.logic.utils import get_rsapi_state
47 46

  
48
from synnefo.api import util
49 47
from synnefo.api import faults
50 48

  
51 49

  
52
def get_image_mock(request, *Args, **kwargs):
53
    return {'backend_id': '1234',
54
            'location': 'pithos://dummyimage',
55
            'disk_format': 'drbd'}
56
util.get_image = get_image_mock
57

  
58

  
59 50
@contextmanager
60 51
def astakos_user(user):
61 52
    """
......
66 57
        .... make api calls ....
67 58

  
68 59
    """
69
    from synnefo.lib import astakos
70
    from synnefo.api import util
71
    orig_method = astakos.get_user
72

  
73 60
    def dummy_get_user(request, *args, **kwargs):
74 61
        request.user = {'username': user, 'groups': []}
75 62
        request.user_uniq = user
76
    astakos.get_user = dummy_get_user
77
    util.get_user = dummy_get_user
78
    yield
79
    astakos.get_user = orig_method
80

  
81

  
82
class AaiClient(Client):
83
    def request(self, **request):
84
        request['HTTP_X_AUTH_TOKEN'] = '0000'
85
        return super(AaiClient, self).request(**request)
86

  
87

  
88
def create_flavors(num):
89
    return [mfactory.FlavorFactory() for x in range(num)]
90 63

  
91

  
92
class APITest(TestCase):
93

  
94
    def test_api_version(self):
95
        """Check API version."""
96
        with astakos_user('user'):
97
            response = self.client.get('/api/v1.1/')
98
        self.assertEqual(response.status_code, 200)
99
        api_version = json.loads(response.content)['version']
100
        self.assertEqual(api_version['id'], 'v1.1')
101
        self.assertEqual(api_version['status'], 'CURRENT')
64
    with patch('synnefo.api.util.get_user') as m:
65
        m.side_effect = dummy_get_user
66
        yield
102 67

  
103 68

  
104
class BaseTestCase(TestCase):
105
    def get(self, url, user='user'):
69
class BaseAPITest(TestCase):
70
    def get(self, url, user='user', *args, **kwargs):
106 71
        with astakos_user(user):
107
            response = self.client.get(url)
72
            response = self.client.get(url, *args, **kwargs)
108 73
        return response
109 74

  
110 75
    def delete(self, url, user='user'):
......
112 77
            response = self.client.delete(url)
113 78
        return response
114 79

  
115
    def post(self, url, user='user', params={}, ctype='json'):
80
    def post(self, url, user='user', params={}, ctype='json', *args, **kwargs):
116 81
        if ctype == 'json':
117 82
            content_type = 'application/json'
118 83
        with astakos_user(user):
119
            response = self.client.post(url, params, content_type=content_type)
84
            response = self.client.post(url, params, content_type=content_type,
85
                                        *args, **kwargs)
120 86
        return response
121 87

  
122
    def put(self, url, user='user', params={}, ctype='json'):
88
    def put(self, url, user='user', params={}, ctype='json', *args, **kwargs):
123 89
        if ctype == 'json':
124 90
            content_type = 'application/json'
125 91
        with astakos_user(user):
126
            response = self.client.put(url, params, content_type=content_type)
92
            response = self.client.put(url, params, content_type=content_type,
93
                    *args, **kwargs)
127 94
        return response
128 95

  
129 96
    def assertSuccess(self, response):
130
        self.assertTrue(response.status_code in [200, 203])
97
        self.assertTrue(response.status_code in [200, 203, 204])
131 98

  
132 99
    def assertFault(self, response, status_code, name):
133 100
        self.assertEqual(response.status_code, status_code)
......
141 108
        self.assertFault(response, 404, 'itemNotFound')
142 109

  
143 110

  
144
class FlavorAPITest(BaseTestCase):
111
class FlavorAPITest(BaseAPITest):
145 112

  
146 113
    def setUp(self):
147 114
        self.flavor1 = mfactory.FlavorFactory()
......
150 117

  
151 118
    def test_flavor_list(self):
152 119
        """Test if the expected list of flavors is returned by."""
153

  
154
        # with astakos_user('user'):
155
        #     response = self.client.get('/api/v1.1/flavors')
156 120
        response = self.get('/api/v1.1/flavors')
121
        self.assertSuccess(response)
157 122

  
158 123
        flavors_from_api = json.loads(response.content)['flavors']['values']
159 124
        flavors_from_db = Flavor.objects.filter(deleted=False)
160 125
        self.assertEqual(len(flavors_from_api), len(flavors_from_db))
161
        self.assertTrue(response.status_code in [200, 203])
162 126
        for flavor_from_api in flavors_from_api:
163 127
            flavor_from_db = Flavor.objects.get(id=flavor_from_api['id'])
164 128
            self.assertEqual(flavor_from_api['id'], flavor_from_db.id)
......
167 131
    def test_flavors_details(self):
168 132
        """Test if the flavors details are returned."""
169 133
        response = self.get('/api/v1.1/flavors/detail')
134
        self.assertSuccess(response)
170 135

  
171 136
        flavors_from_db = Flavor.objects.filter(deleted=False)
172 137
        flavors_from_api = json.loads(response.content)['flavors']['values']
......
190 155
            self.assertEqual(flavor_from_api['name'], flavor_from_db.name)
191 156
            self.assertEqual(flavor_from_api['ram'], flavor_from_db.ram)
192 157

  
193
        # Check if we have the right status_code
194
        self.assertTrue(response.status_code in [200, 203])
195

  
196 158
    def test_flavor_details(self):
197 159
        """Test if the expected flavor is returned."""
198 160
        flavor = self.flavor3
199 161

  
200 162
        response = self.get('/api/v1.1/flavors/%d' % flavor.id)
163
        self.assertSuccess(response)
201 164

  
202 165
        flavor_from_api = json.loads(response.content)['flavor']
203 166
        flavor_from_db = Flavor.objects.get(id=flavor.id)
......
206 169
        self.assertEqual(flavor_from_api['disk'], flavor_from_db.disk)
207 170
        self.assertEqual(flavor_from_api['name'], flavor_from_db.name)
208 171
        self.assertEqual(flavor_from_api['ram'], flavor_from_db.ram)
209
        self.assertTrue(response.status_code in [200, 203])
210 172

  
211 173
    def test_deleted_flavor_details(self):
212 174
        """Test that API returns details for deleted flavors"""
213 175
        flavor = self.flavor2
214 176
        response = self.get('/api/v1.1/flavors/%d' % flavor.id)
177
        self.assertSuccess(response)
215 178
        flavor_from_api = json.loads(response.content)['flavor']
216
        self.assertEqual(response.status_code, 200)
217 179
        self.assertEquals(flavor_from_api['name'], flavor.name)
218 180

  
219 181
    def test_deleted_flavors_list(self):
220 182
        """Test that deleted flavors do not appear to flavors list"""
221 183
        response = self.get('/api/v1.1/flavors')
184
        self.assertSuccess(response)
222 185
        flavors_from_api = json.loads(response.content)['flavors']['values']
223 186
        self.assertEqual(len(flavors_from_api), 2)
224 187

  
......
226 189
        """Test that deleted flavors do not appear to flavors detail list"""
227 190
        mfactory.FlavorFactory(deleted=True)
228 191
        response = self.get('/api/v1.1/flavors/detail')
192
        self.assertSuccess(response)
229 193
        flavors_from_api = json.loads(response.content)['flavors']['values']
230 194
        self.assertEqual(len(flavors_from_api), 2)
231 195

  
......
233 197
        """Test 404 result when requesting a flavor that does not exist."""
234 198

  
235 199
        response = self.get('/api/v1.1/flavors/%d' % 22)
236
        self.assertTrue(response.status_code in [404])
200
        self.assertItemNotFound(response)
237 201

  
238 202

  
239
class ServerAPITest(BaseTestCase):
203
class ServerAPITest(BaseAPITest):
240 204
    def setUp(self):
241 205
        self.user1 = 'user1'
242 206
        self.user2 = 'user2'
......
249 213
    def test_server_list_1(self):
250 214
        """Test if the expected list of servers is returned."""
251 215
        response = self.get('/api/v1.1/servers')
252
        self.assertTrue(response.status_code in [200, 203])
216
        self.assertSuccess(response)
253 217
        servers = json.loads(response.content)['servers']['values']
254 218
        self.assertEqual(servers, [])
255 219

  
256 220
    def test_server_list_2(self):
257 221
        """Test if the expected list of servers is returned."""
258 222
        response = self.get('/api/v1.1/servers', self.user1)
259
        self.assertTrue(response.status_code in [200, 203])
223
        self.assertSuccess(response)
260 224
        servers = json.loads(response.content)['servers']['values']
261 225
        db_server = self.vm1
262 226
        self.assertEqual(servers, [{'name': db_server.name,
......
279 243
            self.assertEqual(api_vm['imageRef'], db_vm.imageid)
280 244
            self.assertEqual(api_vm['name'], db_vm.name)
281 245
            self.assertEqual(api_vm['status'], get_rsapi_state(db_vm))
282
            self.assertTrue(response.status_code in [200, 203])
246
            self.assertSuccess(response)
283 247

  
284 248
    def test_server_detail(self):
285 249
        """Test if a server details are returned."""
......
300 264
        metadata = server['metadata']['values']
301 265
        self.assertEqual(len(metadata), 1)
302 266
        self.assertEqual(metadata[db_vm_meta.meta_key], db_vm_meta.meta_value)
303
        self.assertTrue(response.status_code in [200, 203])
267
        self.assertSuccess(response)
304 268

  
305 269
    def test_noauthorized(self):
306 270
        """Test 404 for detail of other user vm"""
307 271
        db_vm = self.vm2
308 272

  
309 273
        response = self.get('/api/v1.1/servers/%d' % db_vm.id, 'wrong_user')
310
        self.assertEqual(response.status_code, 404)
274
        self.assertItemNotFound(response)
311 275

  
312 276
    def test_wrong_server(self):
313 277
        """Test 404 response if server does not exist."""
314 278
        response = self.get('/api/v1.1/servers/%d' % 5000)
315
        self.assertEqual(response.status_code, 404)
279
        self.assertItemNotFound(response)
316 280

  
317 281
    def test_create_server_empty(self):
318 282
        """Test if the create server call returns a 400 badRequest if
319 283
           no attributes are specified."""
320 284

  
321 285
        response = self.post('/api/v1.1/servers', params={})
322
        self.assertEqual(response.status_code, 400)
286
        self.assertBadRequest(response)
323 287

  
324 288

  
325 289
@patch('synnefo.api.util.get_image')
326 290
@patch('synnefo.logic.rapi_pool.GanetiRapiClient')
327
class ServerCreateAPITest(BaseTestCase):
291
class ServerCreateAPITest(BaseAPITest):
328 292
    def test_create_server(self, mrapi, mimage):
329 293
        """Test if the create server call returns the expected response
330 294
           if a valid request has been speficied."""
......
384 348

  
385 349

  
386 350
@patch('synnefo.logic.rapi_pool.GanetiRapiClient')
387
class ServerDestroyAPITest(BaseTestCase):
351
class ServerDestroyAPITest(BaseAPITest):
388 352
    def test_delete_server(self, mrapi):
389 353
        vm = mfactory.VirtualMachineFactory()
390 354
        response = self.delete('/api/v1.1/servers/%d' % vm.id, vm.userid)
......
400 364

  
401 365
@patch('synnefo.api.util.get_image')
402 366
@patch('synnefo.logic.rapi_pool.GanetiRapiClient')
403
class ServerActionAPITest(BaseTestCase):
367
class ServerActionAPITest(BaseAPITest):
404 368
    def test_actions(self, mrapi, mimage):
405 369
        actions = ['start', 'shutdown', 'reboot']
406 370
        vm = mfactory.VirtualMachineFactory()
......
430 394
        mrapi().ModifyInstance.assert_called_once()
431 395

  
432 396

  
433
class ServerMetadataAPITest(BaseTestCase):
397
class ServerMetadataAPITest(BaseAPITest):
434 398
    def setUp(self):
435 399
        self.vm = mfactory.VirtualMachineFactory()
436 400
        self.metadata = mfactory.VirtualMachineMetadataFactory(vm=self.vm)
......
501 465

  
502 466

  
503 467
@patch('synnefo.logic.rapi_pool.GanetiRapiClient')
504
class NetworkAPITest(BaseTestCase):
468
class NetworkAPITest(BaseAPITest):
505 469
    def setUp(self):
506 470
        self.mac_prefixes = mfactory.MacPrefixPoolTableFactory()
507 471
        self.bridges = mfactory.BridgePoolTableFactory()
......
674 638
        self.assertBadRequest(response)
675 639

  
676 640

  
677
class ServerVNCConsole(BaseTestCase):
641
class ServerVNCConsole(BaseAPITest):
678 642

  
679 643
    def test_not_active_server(self):
680 644
        """Test console req for not ACTIVE server returns badRequest"""
......
702 666
                         set(['type', 'host', 'port', 'password']))
703 667

  
704 668

  
669
def assert_backend_closed(func):
670
    @wraps(func)
671
    def wrapper(self, backend):
672
        result = func(self, backend)
673
        if backend.called is True:
674
            backend.return_value.close.assert_called_once_with()
675
        return result
676
    return wrapper
677

  
678

  
705 679
@patch('synnefo.api.images.ImageBackend')
706
class ImageAPITest(BaseTestCase):
680
class ImageAPITest(BaseAPITest):
681
    @assert_backend_closed
707 682
    def test_create_image(self, mimage):
708 683
        """Test that create image is not implemented"""
709 684
        response = self.post('/api/v1.1/images/', 'user', json.dumps(''),
710 685
                             'json')
711 686
        self.assertEqual(response.status_code, 503)
712 687

  
688
    @assert_backend_closed
713 689
    def test_list_images(self, mimage):
714 690
        """Test that expected list of images is returned"""
715 691
        images = [{'id': 1, 'name': 'image-1'},
......
721 697
        api_images = json.loads(response.content)['images']['values']
722 698
        self.assertEqual(images, api_images)
723 699

  
700
    @assert_backend_closed
724 701
    def test_list_images_detail(self, mimage):
725 702
        images = [{'id': 1,
726 703
                   'name': 'image-1',
......
770 747
        self.assertEqual(len(result_images), len(api_images))
771 748
        self.assertEqual(result_images, api_images)
772 749

  
750
    @assert_backend_closed
773 751
    def test_get_image_details(self, mimage):
774 752
        image = {'id': 42,
775 753
                 'name': 'image-1',
......
793 771
        api_image = json.loads(response.content)['image']
794 772
        self.assertEqual(api_image, result_image)
795 773

  
774
    @assert_backend_closed
796 775
    def test_invalid_image(self, mimage):
797 776
        with patch('synnefo.api.util.get_image') as m:
798 777
            m.side_effect = faults.ItemNotFound('Image not found')
......
804 783
        pass
805 784

  
806 785

  
807
class ImageMetadataAPITest(BaseTestCase):
786
@patch('synnefo.api.util.ImageBackend')
787
class ImageMetadataAPITest(BaseAPITest):
808 788
    def setUp(self):
809 789
        self.image = {'id': 42,
810 790
                 'name': 'image-1',
......
821 801
                   'created': '2012-11-26T11:52:54+00:00',
822 802
                   'updated': '2012-12-26T11:52:54+00:00',
823 803
                   'metadata': {'values': {'foo': 'bar'}}}
824
        self.mock_get_image = Mock('synnefo.api.util.get_image')
825
        self.mock_get_image.result = self.image
826
        self.mock_image_backend = Mock('synnefo.api.images.ImageBackend')
827 804

  
828
    def test_list_metadata(self):
829
        with patch('synnefo.api.util.get_image') as m:
830
            m.return_value = self.image
831
            response = self.get('/api/v1.1/images/42/meta', 'user')
805
    @assert_backend_closed
806
    def test_list_metadata(self, backend):
807
        backend.return_value.get_image.return_value = self.image
808
        response = self.get('/api/v1.1/images/42/meta', 'user')
832 809
        self.assertSuccess(response)
833 810
        meta = json.loads(response.content)['metadata']['values']
834 811
        self.assertEqual(meta, self.image['properties'])
835 812

  
836
    def test_get_metadata(self):
837
        with patch('synnefo.api.util.get_image') as m:
838
            m.return_value = self.image
839
            response = self.get('/api/v1.1/images/42/meta/foo', 'user')
813
    @assert_backend_closed
814
    def test_get_metadata(self, backend):
815
        backend.return_value.get_image.return_value = self.image
816
        response = self.get('/api/v1.1/images/42/meta/foo', 'user')
840 817
        self.assertSuccess(response)
841 818
        meta = json.loads(response.content)['meta']
842 819
        self.assertEqual(meta['foo'], 'bar')
843 820

  
844
    def test_get_invalid_metadata(self):
845
        with patch('synnefo.api.util.get_image') as m:
846
            m.return_value = self.image
847
            response = self.get('/api/v1.1/images/42/meta/not_found', 'user')
821
    @assert_backend_closed
822
    def test_get_invalid_metadata(self, backend):
823
        backend.return_value.get_image.return_value = self.image
824
        response = self.get('/api/v1.1/images/42/meta/not_found', 'user')
848 825
        self.assertItemNotFound(response)
849 826

  
850
    def test_delete_metadata_item(self):
851
        with patch('synnefo.api.util.get_image') as m:
852
            with patch('synnefo.api.images.ImageBackend') as mimage:
853
                m.return_value = self.image
854
                response = self.delete('/api/v1.1/images/42/meta/foo', 'user')
855
                self.assertEqual(response.status_code, 204)
856
                mimage().update.assert_called_once_with('42',
857
                                             {'properties': {'foo2': 'bar2'}})
858

  
859
    def test_create_metadata_item(self):
860
        with patch('synnefo.api.util.get_image') as m:
861
            with patch('synnefo.api.images.ImageBackend') as mimage:
862
                m.return_value = self.image
827
    @assert_backend_closed
828
    def test_delete_metadata_item(self, backend):
829
        backend.return_value.get_image.return_value = self.image
830
        with patch("synnefo.api.images.ImageBackend") as m:
831
            response = self.delete('/api/v1.1/images/42/meta/foo', 'user')
832
            self.assertEqual(response.status_code, 204)
833
            m.return_value.update.assert_called_once_with('42',
834
                                        {'properties': {'foo2': 'bar2'}})
835

  
836
    @assert_backend_closed
837
    def test_create_metadata_item(self, backend):
838
        backend.return_value.get_image.return_value = self.image
839
        with patch("synnefo.api.images.ImageBackend") as m:
863 840
                request = {'meta': {'foo3': 'bar3'}}
864 841
                response = self.put('/api/v1.1/images/42/meta/foo3', 'user',
865 842
                                    json.dumps(request), 'json')
866 843
                self.assertEqual(response.status_code, 201)
867
                mimage().update.assert_called_once_with('42',
844
                m.return_value.update.assert_called_once_with('42',
868 845
                        {'properties':
869 846
                            {'foo': 'bar', 'foo2': 'bar2', 'foo3': 'bar3'}})
870 847

  
871
    def test_update_metadata_item(self):
872
        with patch('synnefo.api.util.get_image') as m:
873
            with patch('synnefo.api.images.ImageBackend') as mimage:
874
                m.return_value = self.image
848
    @assert_backend_closed
849
    def test_update_metadata_item(self, backend):
850
        backend.return_value.get_image.return_value = self.image
851
        with patch("synnefo.api.images.ImageBackend") as m:
875 852
                request = {'metadata': {'foo': 'bar_new', 'foo4': 'bar4'}}
876 853
                response = self.post('/api/v1.1/images/42/meta', 'user',
877 854
                                    json.dumps(request), 'json')
878 855
                self.assertEqual(response.status_code, 201)
879
                mimage().update.assert_called_once_with('42', {'properties':
880
                        {'foo': 'bar_new', 'foo2': 'bar2', 'foo4': 'bar4'}})
856
                m.return_value.update.assert_called_once_with('42',
857
                        {'properties':
858
                            {'foo': 'bar_new', 'foo2': 'bar2', 'foo4': 'bar4'}
859
                        })
860

  
861

  
862
class APITest(TestCase):
863
    def test_api_version(self):
864
        """Check API version."""
865
        with astakos_user('user'):
866
            response = self.client.get('/api/v1.1/')
867
        self.assertEqual(response.status_code, 200)
868
        api_version = json.loads(response.content)['version']
869
        self.assertEqual(api_version['id'], 'v1.1')
870
        self.assertEqual(api_version['status'], 'CURRENT')

Also available in: Unified diff