github.com/misfo/deis@v1.0.1-0.20141111224634-e0eee0392b8a/controller/api/tests/test_config.py (about)

     1  # -*- coding: utf-8 -*-
     2  """
     3  Unit tests for the Deis api app.
     4  
     5  Run the tests with "./manage.py test api"
     6  """
     7  
     8  from __future__ import unicode_literals
     9  
    10  import json
    11  import mock
    12  import requests
    13  
    14  from django.contrib.auth.models import User
    15  from django.test import TransactionTestCase
    16  from rest_framework.authtoken.models import Token
    17  
    18  from api.models import Config
    19  
    20  
    21  def mock_import_repository_task(*args, **kwargs):
    22      resp = requests.Response()
    23      resp.status_code = 200
    24      resp._content_consumed = True
    25      return resp
    26  
    27  
    28  class ConfigTest(TransactionTestCase):
    29  
    30      """Tests setting and updating config values"""
    31  
    32      fixtures = ['tests.json']
    33  
    34      def setUp(self):
    35          self.user = User.objects.get(username='autotest')
    36          self.token = Token.objects.get(user=self.user).key
    37  
    38      @mock.patch('requests.post', mock_import_repository_task)
    39      def test_config(self):
    40          """
    41          Test that config is auto-created for a new app and that
    42          config can be updated using a PATCH
    43          """
    44          url = '/v1/apps'
    45          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    46          self.assertEqual(response.status_code, 201)
    47          app_id = response.data['id']
    48          # check to see that an initial/empty config was created
    49          url = "/v1/apps/{app_id}/config".format(**locals())
    50          response = self.client.get(url,
    51                                     HTTP_AUTHORIZATION='token {}'.format(self.token))
    52          self.assertEqual(response.status_code, 200)
    53          self.assertIn('values', response.data)
    54          self.assertEqual(response.data['values'], {})
    55          config1 = response.data
    56          # set an initial config value
    57          body = {'values': json.dumps({'NEW_URL1': 'http://localhost:8080/'})}
    58          response = self.client.post(url, json.dumps(body), content_type='application/json',
    59                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
    60          self.assertEqual(response.status_code, 201)
    61          config2 = response.data
    62          self.assertNotEqual(config1['uuid'], config2['uuid'])
    63          self.assertIn('NEW_URL1', response.data['values'])
    64          # read the config
    65          response = self.client.get(url,
    66                                     HTTP_AUTHORIZATION='token {}'.format(self.token))
    67          self.assertEqual(response.status_code, 200)
    68          config3 = response.data
    69          self.assertEqual(config2, config3)
    70          self.assertIn('NEW_URL1', response.data['values'])
    71          # set an additional config value
    72          body = {'values': json.dumps({'NEW_URL2': 'http://localhost:8080/'})}
    73          response = self.client.post(url, json.dumps(body), content_type='application/json',
    74                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
    75          self.assertEqual(response.status_code, 201)
    76          config3 = response.data
    77          self.assertNotEqual(config2['uuid'], config3['uuid'])
    78          self.assertIn('NEW_URL1', response.data['values'])
    79          self.assertIn('NEW_URL2', response.data['values'])
    80          # read the config again
    81          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    82          self.assertEqual(response.status_code, 200)
    83          config4 = response.data
    84          self.assertEqual(config3, config4)
    85          self.assertIn('NEW_URL1', response.data['values'])
    86          self.assertIn('NEW_URL2', response.data['values'])
    87          # unset a config value
    88          body = {'values': json.dumps({'NEW_URL2': None})}
    89          response = self.client.post(url, json.dumps(body), content_type='application/json',
    90                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
    91          self.assertEqual(response.status_code, 201)
    92          config5 = response.data
    93          self.assertNotEqual(config4['uuid'], config5['uuid'])
    94          self.assertNotIn('NEW_URL2', json.dumps(response.data['values']))
    95          # unset all config values
    96          body = {'values': json.dumps({'NEW_URL1': None})}
    97          response = self.client.post(url, json.dumps(body), content_type='application/json',
    98                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
    99          self.assertEqual(response.status_code, 201)
   100          self.assertNotIn('NEW_URL1', json.dumps(response.data['values']))
   101          # disallow put/patch/delete
   102          response = self.client.put(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   103          self.assertEqual(response.status_code, 405)
   104          response = self.client.patch(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   105          self.assertEqual(response.status_code, 405)
   106          response = self.client.delete(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   107          self.assertEqual(response.status_code, 405)
   108          return config5
   109  
   110      @mock.patch('requests.post', mock_import_repository_task)
   111      def test_config_set_same_key(self):
   112          """
   113          Test that config sets on the same key function properly
   114          """
   115          url = '/v1/apps'
   116          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   117          self.assertEqual(response.status_code, 201)
   118          app_id = response.data['id']
   119          url = "/v1/apps/{app_id}/config".format(**locals())
   120          # set an initial config value
   121          body = {'values': json.dumps({'PORT': '5000'})}
   122          response = self.client.post(url, json.dumps(body), content_type='application/json',
   123                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   124          self.assertEqual(response.status_code, 201)
   125          self.assertIn('PORT', response.data['values'])
   126          # reset same config value
   127          body = {'values': json.dumps({'PORT': '5001'})}
   128          response = self.client.post(url, json.dumps(body), content_type='application/json',
   129                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   130          self.assertEqual(response.status_code, 201)
   131          self.assertIn('PORT', response.data['values'])
   132          self.assertEqual(response.data['values']['PORT'], '5001')
   133  
   134      @mock.patch('requests.post', mock_import_repository_task)
   135      def test_config_set_unicode(self):
   136          """
   137          Test that config sets with unicode values are accepted.
   138          """
   139          url = '/v1/apps'
   140          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   141          self.assertEqual(response.status_code, 201)
   142          app_id = response.data['id']
   143          url = "/v1/apps/{app_id}/config".format(**locals())
   144          # set an initial config value
   145          body = {'values': json.dumps({'POWERED_BY': 'Деис'})}
   146          response = self.client.post(url, json.dumps(body), content_type='application/json',
   147                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   148          self.assertEqual(response.status_code, 201)
   149          self.assertIn('POWERED_BY', response.data['values'])
   150          # reset same config value
   151          body = {'values': json.dumps({'POWERED_BY': 'Кроликов'})}
   152          response = self.client.post(url, json.dumps(body), content_type='application/json',
   153                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   154          self.assertEqual(response.status_code, 201)
   155          self.assertIn('POWERED_BY', response.data['values'])
   156          self.assertEqual(response.data['values']['POWERED_BY'], 'Кроликов')
   157          # set an integer to test unicode regression
   158          body = {'values': json.dumps({'INTEGER': 1})}
   159          response = self.client.post(url, json.dumps(body), content_type='application/json',
   160                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   161          self.assertEqual(response.status_code, 201)
   162          self.assertIn('INTEGER', response.data['values'])
   163          self.assertEqual(response.data['values']['INTEGER'], 1)
   164  
   165      @mock.patch('requests.post', mock_import_repository_task)
   166      def test_config_str(self):
   167          """Test the text representation of a node."""
   168          config5 = self.test_config()
   169          config = Config.objects.get(uuid=config5['uuid'])
   170          self.assertEqual(str(config), "{}-{}".format(config5['app'], config5['uuid'][:7]))
   171  
   172      @mock.patch('requests.post', mock_import_repository_task)
   173      def test_admin_can_create_config_on_other_apps(self):
   174          """If a non-admin creates an app, an administrator should be able to set config
   175          values for that app.
   176          """
   177          user = User.objects.get(username='autotest2')
   178          token = Token.objects.get(user=user).key
   179          url = '/v1/apps'
   180          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(token))
   181          self.assertEqual(response.status_code, 201)
   182          app_id = response.data['id']
   183          url = "/v1/apps/{app_id}/config".format(**locals())
   184          # set an initial config value
   185          body = {'values': json.dumps({'PORT': '5000'})}
   186          response = self.client.post(url, json.dumps(body), content_type='application/json',
   187                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   188          self.assertEqual(response.status_code, 201)
   189          self.assertIn('PORT', response.data['values'])
   190  
   191      @mock.patch('requests.post', mock_import_repository_task)
   192      def test_limit_memory(self):
   193          """
   194          Test that limit is auto-created for a new app and that
   195          limits can be updated using a PATCH
   196          """
   197          url = '/v1/apps'
   198          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   199          self.assertEqual(response.status_code, 201)
   200          app_id = response.data['id']
   201          url = '/v1/apps/{app_id}/config'.format(**locals())
   202          # check default limit
   203          response = self.client.get(url, content_type='application/json',
   204                                     HTTP_AUTHORIZATION='token {}'.format(self.token))
   205          self.assertEqual(response.status_code, 200)
   206          self.assertIn('memory', response.data)
   207          self.assertEqual(response.data['memory'], {})
   208          # regression test for https://github.com/deis/deis/issues/1563
   209          self.assertNotIn('"', response.data['memory'])
   210          # set an initial limit
   211          mem = {'web': '1G'}
   212          body = {'memory': json.dumps(mem)}
   213          response = self.client.post(url, json.dumps(body), content_type='application/json',
   214                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   215          self.assertEqual(response.status_code, 201)
   216          limit1 = response.data
   217          # check memory limits
   218          response = self.client.get(url, content_type='application/json',
   219                                     HTTP_AUTHORIZATION='token {}'.format(self.token))
   220          self.assertEqual(response.status_code, 200)
   221          self.assertIn('memory', response.data)
   222          memory = response.data['memory']
   223          self.assertIn('web', memory)
   224          self.assertEqual(memory['web'], '1G')
   225          # set an additional value
   226          body = {'memory': json.dumps({'worker': '512M'})}
   227          response = self.client.post(url, json.dumps(body), content_type='application/json',
   228                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   229          self.assertEqual(response.status_code, 201)
   230          limit2 = response.data
   231          self.assertNotEqual(limit1['uuid'], limit2['uuid'])
   232          memory = response.data['memory']
   233          self.assertIn('worker', memory)
   234          self.assertEqual(memory['worker'], '512M')
   235          self.assertIn('web', memory)
   236          self.assertEqual(memory['web'], '1G')
   237          # read the limit again
   238          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   239          self.assertEqual(response.status_code, 200)
   240          limit3 = response.data
   241          self.assertEqual(limit2, limit3)
   242          memory = response.data['memory']
   243          self.assertIn('worker', memory)
   244          self.assertEqual(memory['worker'], '512M')
   245          self.assertIn('web', memory)
   246          self.assertEqual(memory['web'], '1G')
   247          # regression test for https://github.com/deis/deis/issues/1613
   248          # ensure that config:set doesn't wipe out previous limits
   249          body = {'values': json.dumps({'NEW_URL2': 'http://localhost:8080/'})}
   250          response = self.client.post(url, json.dumps(body), content_type='application/json',
   251                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   252          self.assertEqual(response.status_code, 201)
   253          self.assertIn('NEW_URL2', response.data['values'])
   254          # read the limit again
   255          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   256          self.assertEqual(response.status_code, 200)
   257          memory = response.data['memory']
   258          self.assertIn('worker', memory)
   259          self.assertEqual(memory['worker'], '512M')
   260          self.assertIn('web', memory)
   261          self.assertEqual(memory['web'], '1G')
   262          # unset a value
   263          body = {'memory': json.dumps({'worker': None})}
   264          response = self.client.post(url, json.dumps(body), content_type='application/json',
   265                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   266          self.assertEqual(response.status_code, 201)
   267          limit4 = response.data
   268          self.assertNotEqual(limit3['uuid'], limit4['uuid'])
   269          self.assertNotIn('worker', json.dumps(response.data['memory']))
   270          # disallow put/patch/delete
   271          response = self.client.put(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   272          self.assertEqual(response.status_code, 405)
   273          response = self.client.patch(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   274          self.assertEqual(response.status_code, 405)
   275          response = self.client.delete(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   276          self.assertEqual(response.status_code, 405)
   277          return limit4
   278  
   279      @mock.patch('requests.post', mock_import_repository_task)
   280      def test_limit_cpu(self):
   281          """
   282          Test that CPU limits can be set
   283          """
   284          url = '/v1/apps'
   285          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   286          self.assertEqual(response.status_code, 201)
   287          app_id = response.data['id']
   288          url = '/v1/apps/{app_id}/config'.format(**locals())
   289          # check default limit
   290          response = self.client.get(url, content_type='application/json',
   291                                     HTTP_AUTHORIZATION='token {}'.format(self.token))
   292          self.assertEqual(response.status_code, 200)
   293          self.assertIn('cpu', response.data)
   294          self.assertEqual(response.data['cpu'], {})
   295          # regression test for https://github.com/deis/deis/issues/1563
   296          self.assertNotIn('"', response.data['cpu'])
   297          # set an initial limit
   298          body = {'cpu': json.dumps({'web': '1024'})}
   299          response = self.client.post(url, json.dumps(body), content_type='application/json',
   300                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   301          self.assertEqual(response.status_code, 201)
   302          limit1 = response.data
   303          # check memory limits
   304          response = self.client.get(url, content_type='application/json',
   305                                     HTTP_AUTHORIZATION='token {}'.format(self.token))
   306          self.assertEqual(response.status_code, 200)
   307          self.assertIn('cpu', response.data)
   308          cpu = response.data['cpu']
   309          self.assertIn('web', cpu)
   310          self.assertEqual(cpu['web'], '1024')
   311          # set an additional value
   312          body = {'cpu': json.dumps({'worker': '512'})}
   313          response = self.client.post(url, json.dumps(body), content_type='application/json',
   314                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   315          self.assertEqual(response.status_code, 201)
   316          limit2 = response.data
   317          self.assertNotEqual(limit1['uuid'], limit2['uuid'])
   318          cpu = response.data['cpu']
   319          self.assertIn('worker', cpu)
   320          self.assertEqual(cpu['worker'], '512')
   321          self.assertIn('web', cpu)
   322          self.assertEqual(cpu['web'], '1024')
   323          # read the limit again
   324          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   325          self.assertEqual(response.status_code, 200)
   326          limit3 = response.data
   327          self.assertEqual(limit2, limit3)
   328          cpu = response.data['cpu']
   329          self.assertIn('worker', cpu)
   330          self.assertEqual(cpu['worker'], '512')
   331          self.assertIn('web', cpu)
   332          self.assertEqual(cpu['web'], '1024')
   333          # unset a value
   334          body = {'memory': json.dumps({'worker': None})}
   335          response = self.client.post(url, json.dumps(body), content_type='application/json',
   336                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   337          self.assertEqual(response.status_code, 201)
   338          limit4 = response.data
   339          self.assertNotEqual(limit3['uuid'], limit4['uuid'])
   340          self.assertNotIn('worker', json.dumps(response.data['memory']))
   341          # disallow put/patch/delete
   342          response = self.client.put(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   343          self.assertEqual(response.status_code, 405)
   344          response = self.client.patch(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   345          self.assertEqual(response.status_code, 405)
   346          response = self.client.delete(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   347          self.assertEqual(response.status_code, 405)
   348          return limit4
   349  
   350      @mock.patch('requests.post', mock_import_repository_task)
   351      def test_tags(self):
   352          """
   353          Test that tags can be set on an application
   354          """
   355          url = '/v1/apps'
   356          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   357          self.assertEqual(response.status_code, 201)
   358          app_id = response.data['id']
   359          url = '/v1/apps/{app_id}/config'.format(**locals())
   360          # check default
   361          response = self.client.get(url, content_type='application/json',
   362                                     HTTP_AUTHORIZATION='token {}'.format(self.token))
   363          self.assertEqual(response.status_code, 200)
   364          self.assertIn('tags', response.data)
   365          self.assertEqual(response.data['tags'], {})
   366          # set some tags
   367          body = {'tags': json.dumps({'environ': 'dev'})}
   368          response = self.client.post(url, json.dumps(body), content_type='application/json',
   369                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   370          self.assertEqual(response.status_code, 201)
   371          tags1 = response.data
   372          # check tags again
   373          response = self.client.get(url, content_type='application/json',
   374                                     HTTP_AUTHORIZATION='token {}'.format(self.token))
   375          self.assertEqual(response.status_code, 200)
   376          self.assertIn('tags', response.data)
   377          tags = response.data['tags']
   378          self.assertIn('environ', tags)
   379          self.assertEqual(tags['environ'], 'dev')
   380          # set an additional value
   381          body = {'tags': json.dumps({'rack': '1'})}
   382          response = self.client.post(url, json.dumps(body), content_type='application/json',
   383                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   384          self.assertEqual(response.status_code, 201)
   385          tags2 = response.data
   386          self.assertNotEqual(tags1['uuid'], tags2['uuid'])
   387          tags = response.data['tags']
   388          self.assertIn('rack', tags)
   389          self.assertEqual(tags['rack'], '1')
   390          self.assertIn('environ', tags)
   391          self.assertEqual(tags['environ'], 'dev')
   392          # read the limit again
   393          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   394          self.assertEqual(response.status_code, 200)
   395          tags3 = response.data
   396          self.assertEqual(tags2, tags3)
   397          tags = response.data['tags']
   398          self.assertIn('rack', tags)
   399          self.assertEqual(tags['rack'], '1')
   400          self.assertIn('environ', tags)
   401          self.assertEqual(tags['environ'], 'dev')
   402          # unset a value
   403          body = {'tags': json.dumps({'rack': None})}
   404          response = self.client.post(url, json.dumps(body), content_type='application/json',
   405                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   406          self.assertEqual(response.status_code, 201)
   407          tags4 = response.data
   408          self.assertNotEqual(tags3['uuid'], tags4['uuid'])
   409          self.assertNotIn('rack', json.dumps(response.data['tags']))
   410          # set invalid values
   411          body = {'tags': json.dumps({'valid': 'in\nvalid'})}
   412          response = self.client.post(url, json.dumps(body), content_type='application/json',
   413                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   414          self.assertEqual(response.status_code, 400)
   415          body = {'tags': json.dumps({'in.valid': 'valid'})}
   416          response = self.client.post(url, json.dumps(body), content_type='application/json',
   417                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   418          self.assertEqual(response.status_code, 400)
   419          # disallow put/patch/delete
   420          response = self.client.put(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   421          self.assertEqual(response.status_code, 405)
   422          response = self.client.patch(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   423          self.assertEqual(response.status_code, 405)
   424          response = self.client.delete(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   425          self.assertEqual(response.status_code, 405)