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