github.com/jiasir/deis@v1.12.2/controller/api/tests/test_release.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 11 from django.contrib.auth.models import User 12 from django.test import TransactionTestCase 13 import mock 14 from rest_framework.authtoken.models import Token 15 16 from api.models import Release 17 from . import mock_status_ok 18 19 20 @mock.patch('api.models.publish_release', lambda *args: None) 21 class ReleaseTest(TransactionTestCase): 22 23 """Tests push notification from build system""" 24 25 fixtures = ['tests.json'] 26 27 def setUp(self): 28 self.user = User.objects.get(username='autotest') 29 self.token = Token.objects.get(user=self.user).key 30 31 @mock.patch('requests.post', mock_status_ok) 32 def test_release(self): 33 """ 34 Test that a release is created when an app is created, and 35 that updating config or build or triggers a new release 36 """ 37 url = '/v1/apps' 38 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 39 self.assertEqual(response.status_code, 201) 40 app_id = response.data['id'] 41 # check that updating config rolls a new release 42 url = '/v1/apps/{app_id}/config'.format(**locals()) 43 body = {'values': json.dumps({'NEW_URL1': 'http://localhost:8080/'})} 44 response = self.client.post( 45 url, json.dumps(body), content_type='application/json', 46 HTTP_AUTHORIZATION='token {}'.format(self.token)) 47 self.assertEqual(response.status_code, 201) 48 self.assertIn('NEW_URL1', response.data['values']) 49 # check to see that an initial release was created 50 url = '/v1/apps/{app_id}/releases'.format(**locals()) 51 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 52 self.assertEqual(response.status_code, 200) 53 # account for the config release as well 54 self.assertEqual(response.data['count'], 2) 55 url = '/v1/apps/{app_id}/releases/v1'.format(**locals()) 56 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 57 self.assertEqual(response.status_code, 200) 58 release1 = response.data 59 self.assertIn('config', response.data) 60 self.assertIn('build', response.data) 61 self.assertEquals(release1['version'], 1) 62 # check to see that a new release was created 63 url = '/v1/apps/{app_id}/releases/v2'.format(**locals()) 64 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 65 self.assertEqual(response.status_code, 200) 66 release2 = response.data 67 self.assertNotEqual(release1['uuid'], release2['uuid']) 68 self.assertNotEqual(release1['config'], release2['config']) 69 self.assertEqual(release1['build'], release2['build']) 70 self.assertEquals(release2['version'], 2) 71 # check that updating the build rolls a new release 72 url = '/v1/apps/{app_id}/builds'.format(**locals()) 73 build_config = json.dumps({'PATH': 'bin:/usr/local/bin:/usr/bin:/bin'}) 74 body = {'image': 'autotest/example'} 75 response = self.client.post( 76 url, json.dumps(body), content_type='application/json', 77 HTTP_AUTHORIZATION='token {}'.format(self.token)) 78 self.assertEqual(response.status_code, 201) 79 self.assertEqual(response.data['image'], body['image']) 80 # check to see that a new release was created 81 url = '/v1/apps/{app_id}/releases/v3'.format(**locals()) 82 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 83 self.assertEqual(response.status_code, 200) 84 release3 = response.data 85 self.assertNotEqual(release2['uuid'], release3['uuid']) 86 self.assertNotEqual(release2['build'], release3['build']) 87 self.assertEquals(release3['version'], 3) 88 # check that we can fetch a previous release 89 url = '/v1/apps/{app_id}/releases/v2'.format(**locals()) 90 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 91 self.assertEqual(response.status_code, 200) 92 release2 = response.data 93 self.assertNotEqual(release2['uuid'], release3['uuid']) 94 self.assertNotEqual(release2['build'], release3['build']) 95 self.assertEquals(release2['version'], 2) 96 # disallow post/put/patch/delete 97 url = '/v1/apps/{app_id}/releases'.format(**locals()) 98 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 99 self.assertEqual(response.status_code, 405) 100 response = self.client.put(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 101 self.assertEqual(response.status_code, 405) 102 response = self.client.patch(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 103 self.assertEqual(response.status_code, 405) 104 response = self.client.delete(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 105 self.assertEqual(response.status_code, 405) 106 return release3 107 108 @mock.patch('requests.post', mock_status_ok) 109 def test_response_data(self): 110 body = {'id': 'test'} 111 response = self.client.post('/v1/apps', json.dumps(body), 112 content_type='application/json', 113 HTTP_AUTHORIZATION='token {}'.format(self.token)) 114 body = {'values': json.dumps({'NEW_URL': 'http://localhost:8080/'})} 115 config_response = self.client.post('/v1/apps/test/config', json.dumps(body), 116 content_type='application/json', 117 HTTP_AUTHORIZATION='token {}'.format(self.token)) 118 url = '/v1/apps/test/releases/v2' 119 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 120 for key in response.data.keys(): 121 self.assertIn(key, ['uuid', 'owner', 'created', 'updated', 'app', 'build', 'config', 122 'summary', 'version']) 123 expected = { 124 'owner': self.user.username, 125 'app': 'test', 126 'build': None, 127 'config': config_response.data['uuid'], 128 'summary': '{} added NEW_URL'.format(self.user.username), 129 'version': 2 130 } 131 self.assertDictContainsSubset(expected, response.data) 132 133 @mock.patch('requests.post', mock_status_ok) 134 def test_release_rollback(self): 135 url = '/v1/apps' 136 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 137 self.assertEqual(response.status_code, 201) 138 app_id = response.data['id'] 139 # try to rollback with only 1 release extant, expecting 400 140 url = "/v1/apps/{app_id}/releases/rollback/".format(**locals()) 141 response = self.client.post(url, content_type='application/json', 142 HTTP_AUTHORIZATION='token {}'.format(self.token)) 143 self.assertEqual(response.status_code, 400) 144 self.assertEqual(response.data, {'detail': 'version cannot be below 0'}) 145 self.assertEqual(response.get('content-type'), 'application/json') 146 # update config to roll a new release 147 url = '/v1/apps/{app_id}/config'.format(**locals()) 148 body = {'values': json.dumps({'NEW_URL1': 'http://localhost:8080/'})} 149 response = self.client.post( 150 url, json.dumps(body), content_type='application/json', 151 HTTP_AUTHORIZATION='token {}'.format(self.token)) 152 self.assertEqual(response.status_code, 201) 153 # update the build to roll a new release 154 url = '/v1/apps/{app_id}/builds'.format(**locals()) 155 body = {'image': 'autotest/example'} 156 response = self.client.post( 157 url, json.dumps(body), content_type='application/json', 158 HTTP_AUTHORIZATION='token {}'.format(self.token)) 159 self.assertEqual(response.status_code, 201) 160 # rollback and check to see that a 4th release was created 161 # with the build and config of release #2 162 url = "/v1/apps/{app_id}/releases/rollback/".format(**locals()) 163 response = self.client.post(url, content_type='application/json', 164 HTTP_AUTHORIZATION='token {}'.format(self.token)) 165 self.assertEqual(response.status_code, 201) 166 url = '/v1/apps/{app_id}/releases'.format(**locals()) 167 response = self.client.get(url, content_type='application/json', 168 HTTP_AUTHORIZATION='token {}'.format(self.token)) 169 self.assertEqual(response.status_code, 200) 170 self.assertEqual(response.data['count'], 4) 171 url = '/v1/apps/{app_id}/releases/v2'.format(**locals()) 172 response = self.client.get(url, content_type='application/json', 173 HTTP_AUTHORIZATION='token {}'.format(self.token)) 174 self.assertEqual(response.status_code, 200) 175 release2 = response.data 176 self.assertEquals(release2['version'], 2) 177 url = '/v1/apps/{app_id}/releases/v4'.format(**locals()) 178 response = self.client.get(url, content_type='application/json', 179 HTTP_AUTHORIZATION='token {}'.format(self.token)) 180 self.assertEqual(response.status_code, 200) 181 release4 = response.data 182 self.assertEquals(release4['version'], 4) 183 self.assertNotEqual(release2['uuid'], release4['uuid']) 184 self.assertEqual(release2['build'], release4['build']) 185 self.assertEqual(release2['config'], release4['config']) 186 # rollback explicitly to release #1 and check that a 5th release 187 # was created with the build and config of release #1 188 url = "/v1/apps/{app_id}/releases/rollback/".format(**locals()) 189 body = {'version': 1} 190 response = self.client.post( 191 url, json.dumps(body), content_type='application/json', 192 HTTP_AUTHORIZATION='token {}'.format(self.token)) 193 self.assertEqual(response.status_code, 201) 194 url = '/v1/apps/{app_id}/releases'.format(**locals()) 195 response = self.client.get(url, content_type='application/json', 196 HTTP_AUTHORIZATION='token {}'.format(self.token)) 197 self.assertEqual(response.status_code, 200) 198 self.assertEqual(response.data['count'], 5) 199 url = '/v1/apps/{app_id}/releases/v1'.format(**locals()) 200 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 201 self.assertEqual(response.status_code, 200) 202 release1 = response.data 203 url = '/v1/apps/{app_id}/releases/v5'.format(**locals()) 204 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 205 self.assertEqual(response.status_code, 200) 206 release5 = response.data 207 self.assertEqual(release5['version'], 5) 208 self.assertNotEqual(release1['uuid'], release5['uuid']) 209 self.assertEqual(release1['build'], release5['build']) 210 self.assertEqual(release1['config'], release5['config']) 211 # check to see that the current config is actually the initial one 212 url = "/v1/apps/{app_id}/config".format(**locals()) 213 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 214 self.assertEqual(response.status_code, 200) 215 self.assertEqual(response.data['values'], {}) 216 # rollback to #3 and see that it has the correct config 217 url = "/v1/apps/{app_id}/releases/rollback/".format(**locals()) 218 body = {'version': 3} 219 response = self.client.post( 220 url, json.dumps(body), content_type='application/json', 221 HTTP_AUTHORIZATION='token {}'.format(self.token)) 222 self.assertEqual(response.status_code, 201) 223 url = "/v1/apps/{app_id}/config".format(**locals()) 224 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 225 self.assertEqual(response.status_code, 200) 226 values = response.data['values'] 227 self.assertIn('NEW_URL1', values) 228 self.assertEqual('http://localhost:8080/', values['NEW_URL1']) 229 230 @mock.patch('requests.post', mock_status_ok) 231 def test_release_str(self): 232 """Test the text representation of a release.""" 233 release3 = self.test_release() 234 release = Release.objects.get(uuid=release3['uuid']) 235 self.assertEqual(str(release), "{}-v3".format(release3['app'])) 236 237 @mock.patch('requests.post', mock_status_ok) 238 def test_release_summary(self): 239 """Test the text summary of a release.""" 240 release3 = self.test_release() 241 release = Release.objects.get(uuid=release3['uuid']) 242 # check that the release has push and env change messages 243 self.assertIn('autotest deployed ', release.summary) 244 245 @mock.patch('requests.post', mock_status_ok) 246 def test_admin_can_create_release(self): 247 """If a non-user creates an app, an admin should be able to create releases.""" 248 user = User.objects.get(username='autotest2') 249 token = Token.objects.get(user=user).key 250 url = '/v1/apps' 251 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(token)) 252 self.assertEqual(response.status_code, 201) 253 app_id = response.data['id'] 254 # check that updating config rolls a new release 255 url = '/v1/apps/{app_id}/config'.format(**locals()) 256 body = {'values': json.dumps({'NEW_URL1': 'http://localhost:8080/'})} 257 response = self.client.post( 258 url, json.dumps(body), content_type='application/json', 259 HTTP_AUTHORIZATION='token {}'.format(self.token)) 260 self.assertEqual(response.status_code, 201) 261 self.assertIn('NEW_URL1', response.data['values']) 262 # check to see that an initial release was created 263 url = '/v1/apps/{app_id}/releases'.format(**locals()) 264 response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token)) 265 self.assertEqual(response.status_code, 200) 266 # account for the config release as well 267 self.assertEqual(response.data['count'], 2) 268 269 @mock.patch('requests.post', mock_status_ok) 270 def test_unauthorized_user_cannot_modify_release(self): 271 """ 272 An unauthorized user should not be able to modify other releases. 273 274 Since an unauthorized user should not know about the application at all, these 275 requests should return a 404. 276 """ 277 app_id = 'autotest' 278 base_url = '/v1/apps' 279 body = {'id': app_id} 280 response = self.client.post(base_url, json.dumps(body), content_type='application/json', 281 HTTP_AUTHORIZATION='token {}'.format(self.token)) 282 # push a new build 283 url = '{base_url}/{app_id}/builds'.format(**locals()) 284 body = {'image': 'test'} 285 response = self.client.post( 286 url, json.dumps(body), content_type='application/json', 287 HTTP_AUTHORIZATION='token {}'.format(self.token)) 288 # update config to roll a new release 289 url = '{base_url}/{app_id}/config'.format(**locals()) 290 body = {'values': json.dumps({'NEW_URL1': 'http://localhost:8080/'})} 291 response = self.client.post( 292 url, json.dumps(body), content_type='application/json', 293 HTTP_AUTHORIZATION='token {}'.format(self.token)) 294 unauthorized_user = User.objects.get(username='autotest2') 295 unauthorized_token = Token.objects.get(user=unauthorized_user).key 296 # try to rollback 297 url = '{base_url}/{app_id}/releases/rollback/'.format(**locals()) 298 response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(unauthorized_token)) 299 self.assertEqual(response.status_code, 403)