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