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