github.com/tmlbl/deis@v1.0.2/controller/api/tests/test_hooks.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.conf import settings
    14  from django.contrib.auth.models import User
    15  from django.test import TransactionTestCase
    16  from rest_framework.authtoken.models import Token
    17  
    18  
    19  def mock_import_repository_task(*args, **kwargs):
    20      resp = requests.Response()
    21      resp.status_code = 200
    22      resp._content_consumed = True
    23      return resp
    24  
    25  
    26  class HookTest(TransactionTestCase):
    27  
    28      """Tests API hooks used to trigger actions from external components"""
    29  
    30      fixtures = ['tests.json']
    31  
    32      def setUp(self):
    33          self.user = User.objects.get(username='autotest')
    34          self.token = Token.objects.get(user=self.user).key
    35  
    36      def test_push_hook(self):
    37          """Test creating a Push via the API"""
    38          url = '/v1/apps'
    39          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    40          self.assertEqual(response.status_code, 201)
    41          app_id = response.data['id']
    42          # prepare a push body
    43          body = {
    44              'sha': 'df1e628f2244b73f9cdf944f880a2b3470a122f4',
    45              'fingerprint': '88:25:ed:67:56:91:3d:c6:1b:7f:42:c6:9b:41:24:80',
    46              'receive_user': 'autotest',
    47              'receive_repo': '{app_id}'.format(**locals()),
    48              'ssh_connection': '10.0.1.10 50337 172.17.0.143 22',
    49              'ssh_original_command': "git-receive-pack '{app_id}.git'".format(**locals()),
    50          }
    51          # post a request without the auth header
    52          url = "/v1/hooks/push".format(**locals())
    53          response = self.client.post(url, json.dumps(body), content_type='application/json',
    54                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
    55          self.assertEqual(response.status_code, 403)
    56          # now try with the builder key in the special auth header
    57          response = self.client.post(url, json.dumps(body), content_type='application/json',
    58                                      HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY)
    59          self.assertEqual(response.status_code, 201)
    60          for k in ('owner', 'app', 'sha', 'fingerprint', 'receive_repo', 'receive_user',
    61                    'ssh_connection', 'ssh_original_command'):
    62              self.assertIn(k, response.data)
    63  
    64      def test_push_abuse(self):
    65          """Test a user pushing to an unauthorized application"""
    66          # create a legit app as "autotest"
    67          url = '/v1/apps'
    68          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    69          self.assertEqual(response.status_code, 201)
    70          app_id = response.data['id']
    71          # register an evil user
    72          username, password = 'eviluser', 'password'
    73          first_name, last_name = 'Evil', 'User'
    74          email = 'evil@deis.io'
    75          submit = {
    76              'username': username,
    77              'password': password,
    78              'first_name': first_name,
    79              'last_name': last_name,
    80              'email': email,
    81          }
    82          url = '/v1/auth/register'
    83          response = self.client.post(url, json.dumps(submit), content_type='application/json')
    84          self.assertEqual(response.status_code, 201)
    85          # prepare a push body that simulates a git push
    86          body = {
    87              'sha': 'df1e628f2244b73f9cdf944f880a2b3470a122f4',
    88              'fingerprint': '88:25:ed:67:56:91:3d:c6:1b:7f:42:c6:9b:41:24:99',
    89              'receive_user': 'eviluser',
    90              'receive_repo': '{app_id}'.format(**locals()),
    91              'ssh_connection': '10.0.1.10 50337 172.17.0.143 22',
    92              'ssh_original_command': "git-receive-pack '{app_id}.git'".format(**locals()),
    93          }
    94          # try to push as "eviluser"
    95          url = "/v1/hooks/push".format(**locals())
    96          response = self.client.post(url, json.dumps(body), content_type='application/json',
    97                                      HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY)
    98          self.assertEqual(response.status_code, 403)
    99  
   100      @mock.patch('requests.post', mock_import_repository_task)
   101      def test_build_hook(self):
   102          """Test creating a Build via an API Hook"""
   103          url = '/v1/apps'
   104          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   105          self.assertEqual(response.status_code, 201)
   106          app_id = response.data['id']
   107          build = {'username': 'autotest', 'app': app_id}
   108          url = '/v1/hooks/builds'.format(**locals())
   109          body = {'receive_user': 'autotest',
   110                  'receive_repo': app_id,
   111                  'image': '{app_id}:v2'.format(**locals())}
   112          # post the build without an auth token
   113          response = self.client.post(url, json.dumps(body), content_type='application/json')
   114          self.assertEqual(response.status_code, 401)
   115          # post the build with the builder auth key
   116          response = self.client.post(url, json.dumps(body), content_type='application/json',
   117                                      HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY)
   118          self.assertEqual(response.status_code, 200)
   119          self.assertIn('release', response.data)
   120          self.assertIn('version', response.data['release'])
   121          self.assertIn('domains', response.data)
   122  
   123      def test_build_hook_procfile(self):
   124          """Test creating a Procfile build via an API Hook"""
   125          url = '/v1/apps'
   126          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   127          self.assertEqual(response.status_code, 201)
   128          app_id = response.data['id']
   129          build = {'username': 'autotest', 'app': app_id}
   130          url = '/v1/hooks/builds'.format(**locals())
   131          PROCFILE = {'web': 'node server.js', 'worker': 'node worker.js'}
   132          SHA = 'ecdff91c57a0b9ab82e89634df87e293d259a3aa'
   133          body = {'receive_user': 'autotest',
   134                  'receive_repo': app_id,
   135                  'image': '{app_id}:v2'.format(**locals()),
   136                  'sha': SHA,
   137                  'procfile': PROCFILE}
   138          # post the build without an auth token
   139          response = self.client.post(url, json.dumps(body), content_type='application/json')
   140          self.assertEqual(response.status_code, 401)
   141          # post the build with the builder auth key
   142          response = self.client.post(url, json.dumps(body), content_type='application/json',
   143                                      HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY)
   144          self.assertEqual(response.status_code, 200)
   145          self.assertIn('release', response.data)
   146          self.assertIn('version', response.data['release'])
   147          self.assertIn('domains', response.data)
   148          # make sure build fields were populated
   149          url = '/v1/apps/{app_id}/builds'.format(**locals())
   150          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   151          self.assertEqual(response.status_code, 200)
   152          self.assertIn('results', response.data)
   153          build = response.data['results'][0]
   154          self.assertEqual(build['sha'], SHA)
   155          self.assertEqual(build['procfile'], PROCFILE)
   156          # test listing/retrieving container info
   157          url = "/v1/apps/{app_id}/containers/web".format(**locals())
   158          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   159          self.assertEqual(response.status_code, 200)
   160          self.assertEqual(len(response.data['results']), 1)
   161          container = response.data['results'][0]
   162          self.assertEqual(container['type'], 'web')
   163          self.assertEqual(container['num'], 1)
   164  
   165      def test_build_hook_dockerfile(self):
   166          """Test creating a Dockerfile build via an API Hook"""
   167          url = '/v1/apps'
   168          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   169          self.assertEqual(response.status_code, 201)
   170          app_id = response.data['id']
   171          build = {'username': 'autotest', 'app': app_id}
   172          url = '/v1/hooks/builds'.format(**locals())
   173          SHA = 'ecdff91c57a0b9ab82e89634df87e293d259a3aa'
   174          DOCKERFILE = """
   175          FROM busybox
   176          CMD /bin/true
   177          """
   178          body = {'receive_user': 'autotest',
   179                  'receive_repo': app_id,
   180                  'image': '{app_id}:v2'.format(**locals()),
   181                  'sha': SHA,
   182                  'dockerfile': DOCKERFILE}
   183          # post the build without an auth token
   184          response = self.client.post(url, json.dumps(body), content_type='application/json')
   185          self.assertEqual(response.status_code, 401)
   186          # post the build with the builder auth key
   187          response = self.client.post(url, json.dumps(body), content_type='application/json',
   188                                      HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY)
   189          self.assertEqual(response.status_code, 200)
   190          self.assertIn('release', response.data)
   191          self.assertIn('version', response.data['release'])
   192          self.assertIn('domains', response.data)
   193          # make sure build fields were populated
   194          url = '/v1/apps/{app_id}/builds'.format(**locals())
   195          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   196          self.assertEqual(response.status_code, 200)
   197          self.assertIn('results', response.data)
   198          build = response.data['results'][0]
   199          self.assertEqual(build['sha'], SHA)
   200          self.assertEqual(build['dockerfile'], DOCKERFILE)
   201          # test default container
   202          url = "/v1/apps/{app_id}/containers/cmd".format(**locals())
   203          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   204          self.assertEqual(response.status_code, 200)
   205          self.assertEqual(len(response.data['results']), 1)
   206          container = response.data['results'][0]
   207          self.assertEqual(container['type'], 'cmd')
   208          self.assertEqual(container['num'], 1)
   209  
   210      def test_config_hook(self):
   211          """Test reading Config via an API Hook"""
   212          url = '/v1/apps'
   213          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   214          self.assertEqual(response.status_code, 201)
   215          app_id = response.data['id']
   216          url = '/v1/apps/{app_id}/config'.format(**locals())
   217          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   218          self.assertEqual(response.status_code, 200)
   219          self.assertIn('values', response.data)
   220          values = response.data['values']
   221          # prepare the config hook
   222          config = {'username': 'autotest', 'app': app_id}
   223          url = '/v1/hooks/config'.format(**locals())
   224          body = {'receive_user': 'autotest',
   225                  'receive_repo': app_id}
   226          # post without an auth token
   227          response = self.client.post(url, json.dumps(body), content_type='application/json')
   228          self.assertEqual(response.status_code, 401)
   229          # post with the builder auth key
   230          response = self.client.post(url, json.dumps(body), content_type='application/json',
   231                                      HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY)
   232          self.assertEqual(response.status_code, 200)
   233          self.assertIn('values', response.data)
   234          self.assertEqual(values, response.data['values'])
   235  
   236      def test_admin_can_hook(self):
   237          """Administrator should be able to create build hooks on non-admin apps.
   238          """
   239          """Test creating a Push via the API"""
   240          user = User.objects.get(username='autotest2')
   241          token = Token.objects.get(user=user).key
   242          url = '/v1/apps'
   243          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(token))
   244          self.assertEqual(response.status_code, 201)
   245          app_id = response.data['id']
   246          # prepare a push body
   247          DOCKERFILE = """
   248          FROM busybox
   249          CMD /bin/true
   250          """
   251          body = {'receive_user': 'autotest',
   252                  'receive_repo': app_id,
   253                  'image': '{app_id}:v2'.format(**locals()),
   254                  'sha': 'ecdff91c57a0b9ab82e89634df87e293d259a3aa',
   255                  'dockerfile': DOCKERFILE}
   256          url = '/v1/hooks/builds'
   257          response = self.client.post(url, json.dumps(body), content_type='application/json',
   258                                      HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY)
   259          self.assertEqual(response.status_code, 200)
   260          self.assertEqual(response.data['release']['version'], 2)