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)