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)