github.com/tmlbl/deis@v1.0.2/controller/api/tests/test_scheduler.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  from rest_framework.authtoken.models import Token
    15  
    16  from scheduler import chaos
    17  
    18  
    19  class SchedulerTest(TransactionTestCase):
    20      """Tests creation of containers on nodes"""
    21  
    22      fixtures = ['tests.json']
    23  
    24      def setUp(self):
    25          self.user = User.objects.get(username='autotest')
    26          self.token = Token.objects.get(user=self.user).key
    27          # start without any chaos
    28          chaos.CREATE_ERROR_RATE = 0
    29          chaos.DESTROY_ERROR_RATE = 0
    30          chaos.START_ERROR_RATE = 0
    31          chaos.STOP_ERROR_RATE = 0
    32          # use chaos scheduler
    33          settings.SCHEDULER_MODULE = 'chaos'
    34          # provide mock authentication used for run commands
    35          settings.SSH_PRIVATE_KEY = '<some-ssh-private-key>'
    36  
    37      def tearDown(self):
    38          # reset for subsequent tests
    39          settings.SCHEDULER_MODULE = 'mock'
    40          settings.SSH_PRIVATE_KEY = ''
    41  
    42      def test_create_chaos(self):
    43          url = '/v1/apps'
    44          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    45          self.assertEqual(response.status_code, 201)
    46          app_id = response.data['id']
    47          # post a new build
    48          url = "/v1/apps/{app_id}/builds".format(**locals())
    49          body = {'image': 'autotest/example', 'sha': 'a'*40,
    50                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
    51          response = self.client.post(url, json.dumps(body), content_type='application/json',
    52                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
    53          self.assertEqual(response.status_code, 201)
    54          url = "/v1/apps/{app_id}/containers".format(**locals())
    55          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    56          self.assertEqual(response.status_code, 200)
    57          self.assertEqual(len(response.data['results']), 1)
    58          # scale to zero for consistency
    59          url = "/v1/apps/{app_id}/scale".format(**locals())
    60          body = {'web': 0}
    61          response = self.client.post(url, json.dumps(body), content_type='application/json',
    62                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
    63          self.assertEqual(response.status_code, 204)
    64          # let's get chaotic
    65          chaos.CREATE_ERROR_RATE = 0.5
    66          # scale up but expect a 503
    67          url = "/v1/apps/{app_id}/scale".format(**locals())
    68          body = {'web': 20}
    69          response = self.client.post(url, json.dumps(body), content_type='application/json',
    70                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
    71          self.assertEqual(response.status_code, 503)
    72          # inspect broken containers
    73          url = "/v1/apps/{app_id}/containers".format(**locals())
    74          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    75          self.assertEqual(response.status_code, 200)
    76          self.assertEqual(len(response.data['results']), 20)
    77          # make sure some failed
    78          states = set([c['state'] for c in response.data['results']])
    79          self.assertEqual(states, set(['error', 'created']))
    80  
    81      def test_start_chaos(self):
    82          url = '/v1/apps'
    83          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    84          self.assertEqual(response.status_code, 201)
    85          app_id = response.data['id']
    86          # post a new build
    87          url = "/v1/apps/{app_id}/builds".format(**locals())
    88          body = {'image': 'autotest/example', 'sha': 'a'*40,
    89                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
    90          response = self.client.post(url, json.dumps(body), content_type='application/json',
    91                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
    92          self.assertEqual(response.status_code, 201)
    93          url = "/v1/apps/{app_id}/containers".format(**locals())
    94          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    95          self.assertEqual(response.status_code, 200)
    96          self.assertEqual(len(response.data['results']), 1)
    97          # scale to zero for consistency
    98          url = "/v1/apps/{app_id}/scale".format(**locals())
    99          body = {'web': 0}
   100          response = self.client.post(url, json.dumps(body), content_type='application/json',
   101                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   102          self.assertEqual(response.status_code, 204)
   103          # let's get chaotic
   104          chaos.START_ERROR_RATE = 0.5
   105          # scale up, which will allow some crashed containers
   106          url = "/v1/apps/{app_id}/scale".format(**locals())
   107          body = {'web': 20}
   108          response = self.client.post(url, json.dumps(body), content_type='application/json',
   109                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   110          self.assertEqual(response.status_code, 204)
   111          # inspect broken containers
   112          url = "/v1/apps/{app_id}/containers".format(**locals())
   113          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   114          self.assertEqual(response.status_code, 200)
   115          self.assertEqual(len(response.data['results']), 20)
   116          # make sure some failed
   117          states = set([c['state'] for c in response.data['results']])
   118          self.assertEqual(states, set(['crashed', 'up']))
   119  
   120      def test_destroy_chaos(self):
   121          url = '/v1/apps'
   122          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   123          self.assertEqual(response.status_code, 201)
   124          app_id = response.data['id']
   125          # post a new build
   126          url = "/v1/apps/{app_id}/builds".format(**locals())
   127          body = {'image': 'autotest/example', 'sha': 'a'*40,
   128                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   129          response = self.client.post(url, json.dumps(body), content_type='application/json',
   130                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   131          self.assertEqual(response.status_code, 201)
   132          url = "/v1/apps/{app_id}/containers".format(**locals())
   133          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   134          self.assertEqual(response.status_code, 200)
   135          self.assertEqual(len(response.data['results']), 1)
   136          # scale up
   137          url = "/v1/apps/{app_id}/scale".format(**locals())
   138          body = {'web': 20}
   139          response = self.client.post(url, json.dumps(body), content_type='application/json',
   140                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   141          self.assertEqual(response.status_code, 204)
   142          url = "/v1/apps/{app_id}/containers".format(**locals())
   143          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   144          self.assertEqual(response.status_code, 200)
   145          self.assertEqual(len(response.data['results']), 20)
   146          # let's get chaotic
   147          chaos.DESTROY_ERROR_RATE = 0.5
   148          # scale to zero but expect a 503
   149          url = "/v1/apps/{app_id}/scale".format(**locals())
   150          body = {'web': 0}
   151          response = self.client.post(url, json.dumps(body), content_type='application/json',
   152                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   153          self.assertEqual(response.status_code, 503)
   154          # inspect broken containers
   155          url = "/v1/apps/{app_id}/containers".format(**locals())
   156          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   157          self.assertEqual(response.status_code, 200)
   158          states = set([c['state'] for c in response.data['results']])
   159          self.assertEqual(states, set(['error']))
   160          # make sure we can cleanup after enough tries
   161          containers = 20
   162          for _ in range(100):
   163              url = "/v1/apps/{app_id}/scale".format(**locals())
   164              body = {'web': 0}
   165              response = self.client.post(url, json.dumps(body), content_type='application/json',
   166                                          HTTP_AUTHORIZATION='token {}'.format(self.token))
   167              # break if we destroyed successfully
   168              if response.status_code == 204:
   169                  break
   170              self.assertEquals(response.status_code, 503)
   171              # inspect broken containers
   172              url = "/v1/apps/{app_id}/containers".format(**locals())
   173              response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   174              self.assertEqual(response.status_code, 200)
   175              containers = len(response.data['results'])
   176  
   177      def test_build_chaos(self):
   178          url = '/v1/apps'
   179          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   180          self.assertEqual(response.status_code, 201)
   181          app_id = response.data['id']
   182          # post a new build
   183          url = "/v1/apps/{app_id}/builds".format(**locals())
   184          body = {'image': 'autotest/example', 'sha': 'a'*40,
   185                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   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          # inspect builds
   190          url = "/v1/apps/{app_id}/builds".format(**locals())
   191          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   192          self.assertEqual(response.status_code, 200)
   193          self.assertEqual(len(response.data['results']), 1)
   194          # inspect releases
   195          url = "/v1/apps/{app_id}/releases".format(**locals())
   196          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   197          self.assertEqual(response.status_code, 200)
   198          self.assertEqual(len(response.data['results']), 2)
   199          url = "/v1/apps/{app_id}/containers".format(**locals())
   200          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   201          self.assertEqual(response.status_code, 200)
   202          self.assertEqual(len(response.data['results']), 1)
   203          # scale up
   204          url = "/v1/apps/{app_id}/scale".format(**locals())
   205          body = {'web': 20}
   206          response = self.client.post(url, json.dumps(body), content_type='application/json',
   207                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   208          self.assertEqual(response.status_code, 204)
   209          # simulate failing to create containers
   210          chaos.CREATE_ERROR_RATE = 0.5
   211          chaos.START_ERROR_RATE = 0.5
   212          # post a new build
   213          url = "/v1/apps/{app_id}/builds".format(**locals())
   214          body = {'image': 'autotest/example', 'sha': 'b'*40,
   215                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   216          response = self.client.post(url, json.dumps(body), content_type='application/json',
   217                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   218          self.assertEqual(response.status_code, 503)
   219          # inspect releases
   220          url = "/v1/apps/{app_id}/releases".format(**locals())
   221          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   222          self.assertEqual(response.status_code, 200)
   223          self.assertEqual(len(response.data['results']), 2)
   224          # inspect containers
   225          url = "/v1/apps/{app_id}/containers".format(**locals())
   226          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   227          self.assertEqual(response.status_code, 200)
   228          self.assertEqual(len(response.data['results']), 20)
   229  
   230          # make sure all old containers are still up
   231          states = set([c['state'] for c in response.data['results']])
   232          self.assertEqual(states, set(['up']))
   233  
   234      def test_config_chaos(self):
   235          url = '/v1/apps'
   236          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   237          self.assertEqual(response.status_code, 201)
   238          app_id = response.data['id']
   239          # post a new build
   240          url = "/v1/apps/{app_id}/builds".format(**locals())
   241          body = {'image': 'autotest/example', 'sha': 'a'*40,
   242                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   243          response = self.client.post(url, json.dumps(body), content_type='application/json',
   244                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   245          self.assertEqual(response.status_code, 201)
   246          # inspect releases
   247          url = "/v1/apps/{app_id}/releases".format(**locals())
   248          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   249          self.assertEqual(response.status_code, 200)
   250          self.assertEqual(len(response.data['results']), 2)
   251          url = "/v1/apps/{app_id}/containers".format(**locals())
   252          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   253          self.assertEqual(response.status_code, 200)
   254          self.assertEqual(len(response.data['results']), 1)
   255          # scale up
   256          url = "/v1/apps/{app_id}/scale".format(**locals())
   257          body = {'web': 20}
   258          response = self.client.post(url, json.dumps(body), content_type='application/json',
   259                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   260          self.assertEqual(response.status_code, 204)
   261          # simulate failing to create or start containers
   262          chaos.CREATE_ERROR_RATE = 0.5
   263          chaos.START_ERROR_RATE = 0.5
   264          # post a new config
   265          url = "/v1/apps/{app_id}/config".format(**locals())
   266          body = {'values': json.dumps({'NEW_URL1': 'http://localhost:8080/'})}
   267          response = self.client.post(url, json.dumps(body), content_type='application/json',
   268                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   269          self.assertEqual(response.status_code, 503)
   270          # inspect releases
   271          url = "/v1/apps/{app_id}/releases".format(**locals())
   272          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   273          self.assertEqual(response.status_code, 200)
   274          self.assertEqual(len(response.data['results']), 2)
   275          # inspect containers
   276          url = "/v1/apps/{app_id}/containers".format(**locals())
   277          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   278          self.assertEqual(response.status_code, 200)
   279          self.assertEqual(len(response.data['results']), 20)
   280          # make sure all old containers are still up
   281          states = set([c['state'] for c in response.data['results']])
   282          self.assertEqual(states, set(['up']))
   283  
   284      def test_run_chaos(self):
   285          url = '/v1/apps'
   286          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   287          self.assertEqual(response.status_code, 201)
   288          app_id = response.data['id']
   289          # post a new build
   290          url = "/v1/apps/{app_id}/builds".format(**locals())
   291          body = {'image': 'autotest/example', 'sha': 'a'*40,
   292                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   293          response = self.client.post(url, json.dumps(body), content_type='application/json',
   294                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   295          self.assertEqual(response.status_code, 201)
   296          # inspect builds
   297          url = "/v1/apps/{app_id}/builds".format(**locals())
   298          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   299          self.assertEqual(response.status_code, 200)
   300          self.assertEqual(len(response.data['results']), 1)
   301          # inspect releases
   302          url = "/v1/apps/{app_id}/releases".format(**locals())
   303          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   304          self.assertEqual(response.status_code, 200)
   305          self.assertEqual(len(response.data['results']), 2)
   306          url = "/v1/apps/{app_id}/containers".format(**locals())
   307          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   308          self.assertEqual(response.status_code, 200)
   309          self.assertEqual(len(response.data['results']), 1)
   310          # block all create operations
   311          chaos.CREATE_ERROR_RATE = 1
   312          # make sure the run fails with a 503
   313          url = '/v1/apps/{app_id}/run'.format(**locals())
   314          body = {'command': 'ls -al'}
   315          response = self.client.post(url, json.dumps(body), content_type='application/json',
   316                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   317          self.assertEqual(response.status_code, 503)