github.com/amrnt/deis@v1.3.1/controller/api/tests/test_build.py (about) 1 """ 2 Unit tests for the Deis api app. 3 4 Run the tests with "./manage.py test api" 5 """ 6 7 from __future__ import unicode_literals 8 9 import json 10 import mock 11 import requests 12 13 from django.contrib.auth.models import User 14 from django.test import TransactionTestCase 15 from rest_framework.authtoken.models import Token 16 17 from api.models import Build 18 19 20 def mock_import_repository_task(*args, **kwargs): 21 resp = requests.Response() 22 resp.status_code = 200 23 resp._content_consumed = True 24 return resp 25 26 27 class BuildTest(TransactionTestCase): 28 29 """Tests build notification from build system""" 30 31 fixtures = ['tests.json'] 32 33 def setUp(self): 34 self.user = User.objects.get(username='autotest') 35 self.token = Token.objects.get(user=self.user).key 36 37 @mock.patch('requests.post', mock_import_repository_task) 38 def test_build(self): 39 """ 40 Test that a null build is created and that users can post new builds 41 """ 42 url = '/v1/apps' 43 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 44 self.assertEqual(response.status_code, 201) 45 app_id = response.data['id'] 46 # check to see that no initial build was created 47 url = "/v1/apps/{app_id}/builds".format(**locals()) 48 response = self.client.get(url, 49 HTTP_AUTHORIZATION='token {}'.format(self.token)) 50 self.assertEqual(response.status_code, 200) 51 self.assertEqual(response.data['count'], 0) 52 # post a new build 53 body = {'image': 'autotest/example'} 54 response = self.client.post(url, json.dumps(body), content_type='application/json', 55 HTTP_AUTHORIZATION='token {}'.format(self.token)) 56 self.assertEqual(response.status_code, 201) 57 build_id = response.data['uuid'] 58 build1 = response.data 59 self.assertEqual(response.data['image'], body['image']) 60 # read the build 61 url = "/v1/apps/{app_id}/builds/{build_id}".format(**locals()) 62 response = self.client.get(url, 63 HTTP_AUTHORIZATION='token {}'.format(self.token)) 64 self.assertEqual(response.status_code, 200) 65 build2 = response.data 66 self.assertEqual(build1, build2) 67 # post a new build 68 url = "/v1/apps/{app_id}/builds".format(**locals()) 69 body = {'image': 'autotest/example'} 70 response = self.client.post(url, json.dumps(body), content_type='application/json', 71 HTTP_AUTHORIZATION='token {}'.format(self.token)) 72 self.assertEqual(response.status_code, 201) 73 self.assertIn('x-deis-release', response._headers) 74 build3 = response.data 75 self.assertEqual(response.data['image'], body['image']) 76 self.assertNotEqual(build2['uuid'], build3['uuid']) 77 # disallow put/patch/delete 78 response = self.client.put(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 79 self.assertEqual(response.status_code, 405) 80 response = self.client.patch(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 81 self.assertEqual(response.status_code, 405) 82 response = self.client.delete(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 83 self.assertEqual(response.status_code, 405) 84 85 @mock.patch('requests.post', mock_import_repository_task) 86 def test_response_data(self): 87 """Test that the serialized response contains only relevant data.""" 88 body = {'id': 'test'} 89 url = '/v1/apps' 90 response = self.client.post(url, json.dumps(body), 91 content_type='application/json', 92 HTTP_AUTHORIZATION='token {}'.format(self.token)) 93 # post an image as a build 94 url = "/v1/apps/test/builds".format(**locals()) 95 body = {'image': 'autotest/example'} 96 response = self.client.post(url, json.dumps(body), content_type='application/json', 97 HTTP_AUTHORIZATION='token {}'.format(self.token)) 98 for key in response.data.keys(): 99 self.assertIn(key, ['uuid', 'owner', 'created', 'updated', 'app', 'dockerfile', 100 'image', 'procfile', 'sha']) 101 expected = { 102 'owner': self.user.username, 103 'app': 'test', 104 'dockerfile': '', 105 'image': 'autotest/example', 106 'procfile': {}, 107 'sha': '' 108 } 109 self.assertDictContainsSubset(expected, response.data) 110 111 @mock.patch('requests.post', mock_import_repository_task) 112 def test_build_default_containers(self): 113 url = '/v1/apps' 114 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 115 self.assertEqual(response.status_code, 201) 116 app_id = response.data['id'] 117 # post an image as a build 118 url = "/v1/apps/{app_id}/builds".format(**locals()) 119 body = {'image': 'autotest/example'} 120 response = self.client.post(url, json.dumps(body), content_type='application/json', 121 HTTP_AUTHORIZATION='token {}'.format(self.token)) 122 self.assertEqual(response.status_code, 201) 123 url = "/v1/apps/{app_id}/containers/cmd".format(**locals()) 124 response = self.client.get(url, 125 HTTP_AUTHORIZATION='token {}'.format(self.token)) 126 self.assertEqual(response.status_code, 200) 127 self.assertEqual(len(response.data['results']), 1) 128 container = response.data['results'][0] 129 self.assertEqual(container['type'], 'cmd') 130 self.assertEqual(container['num'], 1) 131 # start with a new app 132 url = '/v1/apps' 133 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 134 self.assertEqual(response.status_code, 201) 135 app_id = response.data['id'] 136 # post a new build with procfile 137 url = "/v1/apps/{app_id}/builds".format(**locals()) 138 body = {'image': 'autotest/example', 139 'sha': 'a'*40, 140 'dockerfile': "FROM scratch"} 141 response = self.client.post(url, json.dumps(body), content_type='application/json', 142 HTTP_AUTHORIZATION='token {}'.format(self.token)) 143 self.assertEqual(response.status_code, 201) 144 url = "/v1/apps/{app_id}/containers/cmd".format(**locals()) 145 response = self.client.get(url, 146 HTTP_AUTHORIZATION='token {}'.format(self.token)) 147 self.assertEqual(response.status_code, 200) 148 self.assertEqual(len(response.data['results']), 1) 149 container = response.data['results'][0] 150 self.assertEqual(container['type'], 'cmd') 151 self.assertEqual(container['num'], 1) 152 # start with a new app 153 url = '/v1/apps' 154 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 155 self.assertEqual(response.status_code, 201) 156 app_id = response.data['id'] 157 # post a new build with procfile 158 url = "/v1/apps/{app_id}/builds".format(**locals()) 159 body = {'image': 'autotest/example', 160 'sha': 'a'*40, 161 'dockerfile': "FROM scratch", 162 'procfile': {'worker': 'node worker.js'}} 163 response = self.client.post(url, json.dumps(body), content_type='application/json', 164 HTTP_AUTHORIZATION='token {}'.format(self.token)) 165 self.assertEqual(response.status_code, 201) 166 url = "/v1/apps/{app_id}/containers/cmd".format(**locals()) 167 response = self.client.get(url, 168 HTTP_AUTHORIZATION='token {}'.format(self.token)) 169 self.assertEqual(response.status_code, 200) 170 self.assertEqual(len(response.data['results']), 1) 171 container = response.data['results'][0] 172 self.assertEqual(container['type'], 'cmd') 173 self.assertEqual(container['num'], 1) 174 # start with a new app 175 url = '/v1/apps' 176 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 177 self.assertEqual(response.status_code, 201) 178 app_id = response.data['id'] 179 # post a new build with procfile 180 url = "/v1/apps/{app_id}/builds".format(**locals()) 181 body = {'image': 'autotest/example', 182 'sha': 'a'*40, 183 'procfile': json.dumps({'web': 'node server.js', 184 'worker': 'node worker.js'})} 185 response = self.client.post(url, json.dumps(body), content_type='application/json', 186 HTTP_AUTHORIZATION='token {}'.format(self.token)) 187 self.assertEqual(response.status_code, 201) 188 url = "/v1/apps/{app_id}/containers/web".format(**locals()) 189 response = self.client.get(url, 190 HTTP_AUTHORIZATION='token {}'.format(self.token)) 191 self.assertEqual(response.status_code, 200) 192 self.assertEqual(len(response.data['results']), 1) 193 container = response.data['results'][0] 194 self.assertEqual(container['type'], 'web') 195 self.assertEqual(container['num'], 1) 196 197 @mock.patch('requests.post', mock_import_repository_task) 198 def test_build_str(self): 199 """Test the text representation of a build.""" 200 url = '/v1/apps' 201 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 202 self.assertEqual(response.status_code, 201) 203 app_id = response.data['id'] 204 # post a new build 205 url = "/v1/apps/{app_id}/builds".format(**locals()) 206 body = {'image': 'autotest/example'} 207 response = self.client.post(url, json.dumps(body), content_type='application/json', 208 HTTP_AUTHORIZATION='token {}'.format(self.token)) 209 self.assertEqual(response.status_code, 201) 210 build = Build.objects.get(uuid=response.data['uuid']) 211 self.assertEqual(str(build), "{}-{}".format( 212 response.data['app'], response.data['uuid'][:7])) 213 214 @mock.patch('requests.post', mock_import_repository_task) 215 def test_admin_can_create_builds_on_other_apps(self): 216 """If a user creates an application, an administrator should be able 217 to push builds. 218 """ 219 # create app as non-admin 220 user = User.objects.get(username='autotest2') 221 token = Token.objects.get(user=user).key 222 url = '/v1/apps' 223 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(token)) 224 self.assertEqual(response.status_code, 201) 225 app_id = response.data['id'] 226 # post a new build as admin 227 url = "/v1/apps/{app_id}/builds".format(**locals()) 228 body = {'image': 'autotest/example'} 229 response = self.client.post(url, json.dumps(body), content_type='application/json', 230 HTTP_AUTHORIZATION='token {}'.format(self.token)) 231 self.assertEqual(response.status_code, 201) 232 build = Build.objects.get(uuid=response.data['uuid']) 233 self.assertEqual(str(build), "{}-{}".format( 234 response.data['app'], response.data['uuid'][:7])) 235 236 @mock.patch('requests.post', mock_import_repository_task) 237 def test_unauthorized_user_cannot_modify_build(self): 238 """ 239 An unauthorized user should not be able to modify other builds. 240 241 Since an unauthorized user can't access the application, these 242 requests should return a 403. 243 """ 244 app_id = 'autotest' 245 url = '/v1/apps' 246 body = {'id': app_id} 247 response = self.client.post(url, json.dumps(body), content_type='application/json', 248 HTTP_AUTHORIZATION='token {}'.format(self.token)) 249 unauthorized_user = User.objects.get(username='autotest2') 250 unauthorized_token = Token.objects.get(user=unauthorized_user).key 251 url = '{}/{}/builds'.format(url, app_id) 252 body = {'image': 'foo'} 253 response = self.client.post(url, json.dumps(body), content_type='application/json', 254 HTTP_AUTHORIZATION='token {}'.format(unauthorized_token)) 255 self.assertEqual(response.status_code, 403)