github.com/ahjdzx/deis@v1.1.1/controller/api/tests/test_container.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.contrib.auth.models import User
    14  from django.test import TransactionTestCase
    15  from django_fsm import TransitionNotAllowed
    16  from rest_framework.authtoken.models import Token
    17  
    18  from api.models import App, Build, Container, Release
    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 ContainerTest(TransactionTestCase):
    29      """Tests creation of containers on nodes"""
    30  
    31      fixtures = ['tests.json']
    32  
    33      def setUp(self):
    34          self.user = User.objects.get(username='autotest')
    35          self.token = Token.objects.get(user=self.user).key
    36  
    37      def test_container_state_good(self):
    38          """Test that the finite state machine transitions with a good scheduler"""
    39          url = '/v1/apps'
    40          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    41          self.assertEqual(response.status_code, 201)
    42          app_id = response.data['id']
    43          app = App.objects.get(id=app_id)
    44          user = User.objects.get(username='autotest')
    45          build = Build.objects.create(owner=user, app=app, image="qwerty")
    46          # create an initial release
    47          release = Release.objects.create(version=2,
    48                                           owner=user,
    49                                           app=app,
    50                                           config=app.config_set.latest(),
    51                                           build=build)
    52          # create a container
    53          c = Container.objects.create(owner=user,
    54                                       app=app,
    55                                       release=release,
    56                                       type='web',
    57                                       num=1)
    58          self.assertEqual(c.state, 'initialized')
    59          # test an illegal transition
    60          self.assertRaises(TransitionNotAllowed, lambda: c.start())
    61          c.create()
    62          self.assertEqual(c.state, 'created')
    63          c.start()
    64          self.assertEqual(c.state, 'up')
    65          c.destroy()
    66          self.assertEqual(c.state, 'destroyed')
    67  
    68      def test_container_state_protected(self):
    69          """Test that you cannot directly modify the state"""
    70          url = '/v1/apps'
    71          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    72          self.assertEqual(response.status_code, 201)
    73          app_id = response.data['id']
    74          app = App.objects.get(id=app_id)
    75          user = User.objects.get(username='autotest')
    76          build = Build.objects.create(owner=user, app=app, image="qwerty")
    77          # create an initial release
    78          release = Release.objects.create(version=2,
    79                                           owner=user,
    80                                           app=app,
    81                                           config=app.config_set.latest(),
    82                                           build=build)
    83          # create a container
    84          c = Container.objects.create(owner=user,
    85                                       app=app,
    86                                       release=release,
    87                                       type='web',
    88                                       num=1)
    89          self.assertRaises(AttributeError, lambda: setattr(c, 'state', 'up'))
    90  
    91      def test_container_api_heroku(self):
    92          url = '/v1/apps'
    93          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    94          self.assertEqual(response.status_code, 201)
    95          app_id = response.data['id']
    96          # should start with zero
    97          url = "/v1/apps/{app_id}/containers".format(**locals())
    98          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
    99          self.assertEqual(response.status_code, 200)
   100          self.assertEqual(len(response.data['results']), 0)
   101          # post a new build
   102          url = "/v1/apps/{app_id}/builds".format(**locals())
   103          body = {'image': 'autotest/example', 'sha': 'a'*40,
   104                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   105          response = self.client.post(url, json.dumps(body), content_type='application/json',
   106                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   107          self.assertEqual(response.status_code, 201)
   108          # scale up
   109          url = "/v1/apps/{app_id}/scale".format(**locals())
   110          # test setting one proc type at a time
   111          body = {'web': 4}
   112          response = self.client.post(url, json.dumps(body), content_type='application/json',
   113                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   114          self.assertEqual(response.status_code, 204)
   115          body = {'worker': 2}
   116          response = self.client.post(url, json.dumps(body), content_type='application/json',
   117                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   118          self.assertEqual(response.status_code, 204)
   119          url = "/v1/apps/{app_id}/containers".format(**locals())
   120          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   121          self.assertEqual(response.status_code, 200)
   122          self.assertEqual(len(response.data['results']), 6)
   123          url = "/v1/apps/{app_id}".format(**locals())
   124          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   125          self.assertEqual(response.status_code, 200)
   126          # ensure the structure field is up-to-date
   127          self.assertEqual(response.data['structure']['web'], 4)
   128          self.assertEqual(response.data['structure']['worker'], 2)
   129          # test listing/retrieving container info
   130          url = "/v1/apps/{app_id}/containers/web".format(**locals())
   131          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   132          self.assertEqual(response.status_code, 200)
   133          self.assertEqual(len(response.data['results']), 4)
   134          num = response.data['results'][0]['num']
   135          url = "/v1/apps/{app_id}/containers/web/{num}".format(**locals())
   136          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   137          self.assertEqual(response.status_code, 200)
   138          self.assertEqual(response.data['num'], num)
   139          # scale down
   140          url = "/v1/apps/{app_id}/scale".format(**locals())
   141          # test setting two proc types at a time
   142          body = {'web': 2, 'worker': 1}
   143          response = self.client.post(url, json.dumps(body), content_type='application/json',
   144                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   145          self.assertEqual(response.status_code, 204)
   146          url = "/v1/apps/{app_id}/containers".format(**locals())
   147          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   148          self.assertEqual(response.status_code, 200)
   149          self.assertEqual(len(response.data['results']), 3)
   150          self.assertEqual(max(c['num'] for c in response.data['results']), 2)
   151          url = "/v1/apps/{app_id}".format(**locals())
   152          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   153          self.assertEqual(response.status_code, 200)
   154          # ensure the structure field is up-to-date
   155          self.assertEqual(response.data['structure']['web'], 2)
   156          self.assertEqual(response.data['structure']['worker'], 1)
   157          # scale down to 0
   158          url = "/v1/apps/{app_id}/scale".format(**locals())
   159          body = {'web': 0, 'worker': 0}
   160          response = self.client.post(url, json.dumps(body), content_type='application/json',
   161                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   162          self.assertEqual(response.status_code, 204)
   163          url = "/v1/apps/{app_id}/containers".format(**locals())
   164          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   165          self.assertEqual(response.status_code, 200)
   166          self.assertEqual(len(response.data['results']), 0)
   167          url = "/v1/apps/{app_id}".format(**locals())
   168          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   169          self.assertEqual(response.status_code, 200)
   170  
   171      @mock.patch('requests.post', mock_import_repository_task)
   172      def test_container_api_docker(self):
   173          url = '/v1/apps'
   174          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   175          self.assertEqual(response.status_code, 201)
   176          app_id = response.data['id']
   177          # should start with zero
   178          url = "/v1/apps/{app_id}/containers".format(**locals())
   179          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   180          self.assertEqual(response.status_code, 200)
   181          self.assertEqual(len(response.data['results']), 0)
   182          # post a new build
   183          url = "/v1/apps/{app_id}/builds".format(**locals())
   184          body = {'image': 'autotest/example', 'dockerfile': "FROM busybox\nCMD /bin/true"}
   185          response = self.client.post(url, json.dumps(body), content_type='application/json',
   186                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   187          self.assertEqual(response.status_code, 201)
   188          # scale up
   189          url = "/v1/apps/{app_id}/scale".format(**locals())
   190          body = {'cmd': 6}
   191          response = self.client.post(url, json.dumps(body), content_type='application/json',
   192                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   193          self.assertEqual(response.status_code, 204)
   194          url = "/v1/apps/{app_id}/containers".format(**locals())
   195          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   196          self.assertEqual(response.status_code, 200)
   197          self.assertEqual(len(response.data['results']), 6)
   198          url = "/v1/apps/{app_id}".format(**locals())
   199          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   200          self.assertEqual(response.status_code, 200)
   201          # test listing/retrieving container info
   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']), 6)
   206          # scale down
   207          url = "/v1/apps/{app_id}/scale".format(**locals())
   208          body = {'cmd': 3}
   209          response = self.client.post(url, json.dumps(body), content_type='application/json',
   210                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   211          self.assertEqual(response.status_code, 204)
   212          url = "/v1/apps/{app_id}/containers".format(**locals())
   213          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   214          self.assertEqual(response.status_code, 200)
   215          self.assertEqual(len(response.data['results']), 3)
   216          self.assertEqual(max(c['num'] for c in response.data['results']), 3)
   217          url = "/v1/apps/{app_id}".format(**locals())
   218          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   219          self.assertEqual(response.status_code, 200)
   220          # scale down to 0
   221          url = "/v1/apps/{app_id}/scale".format(**locals())
   222          body = {'cmd': 0}
   223          response = self.client.post(url, json.dumps(body), content_type='application/json',
   224                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   225          self.assertEqual(response.status_code, 204)
   226          url = "/v1/apps/{app_id}/containers".format(**locals())
   227          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   228          self.assertEqual(response.status_code, 200)
   229          self.assertEqual(len(response.data['results']), 0)
   230          url = "/v1/apps/{app_id}".format(**locals())
   231          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   232          self.assertEqual(response.status_code, 200)
   233  
   234      @mock.patch('requests.post', mock_import_repository_task)
   235      def test_container_release(self):
   236          url = '/v1/apps'
   237          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   238          self.assertEqual(response.status_code, 201)
   239          app_id = response.data['id']
   240          # should start with zero
   241          url = "/v1/apps/{app_id}/containers".format(**locals())
   242          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   243          self.assertEqual(response.status_code, 200)
   244          self.assertEqual(len(response.data['results']), 0)
   245          # post a new build
   246          url = "/v1/apps/{app_id}/builds".format(**locals())
   247          body = {'image': 'autotest/example', 'sha': 'a'*40,
   248                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   249          response = self.client.post(url, json.dumps(body), content_type='application/json',
   250                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   251          self.assertEqual(response.status_code, 201)
   252          # scale up
   253          url = "/v1/apps/{app_id}/scale".format(**locals())
   254          body = {'web': 1}
   255          response = self.client.post(url, json.dumps(body), content_type='application/json',
   256                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   257          self.assertEqual(response.status_code, 204)
   258          url = "/v1/apps/{app_id}/containers".format(**locals())
   259          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   260          self.assertEqual(response.status_code, 200)
   261          self.assertEqual(len(response.data['results']), 1)
   262          self.assertEqual(response.data['results'][0]['release'], 'v2')
   263          # post a new build
   264          url = "/v1/apps/{app_id}/builds".format(**locals())
   265          body = {'image': 'autotest/example'}
   266          response = self.client.post(url, json.dumps(body), content_type='application/json',
   267                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   268          self.assertEqual(response.status_code, 201)
   269          self.assertEqual(response.data['image'], body['image'])
   270          url = "/v1/apps/{app_id}/containers".format(**locals())
   271          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   272          self.assertEqual(response.status_code, 200)
   273          self.assertEqual(len(response.data['results']), 1)
   274          self.assertEqual(response.data['results'][0]['release'], 'v3')
   275          # post new config
   276          url = "/v1/apps/{app_id}/config".format(**locals())
   277          body = {'values': json.dumps({'KEY': 'value'})}
   278          response = self.client.post(url, json.dumps(body), content_type='application/json',
   279                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   280          self.assertEqual(response.status_code, 201)
   281          url = "/v1/apps/{app_id}/containers".format(**locals())
   282          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   283          self.assertEqual(response.status_code, 200)
   284          self.assertEqual(len(response.data['results']), 1)
   285          self.assertEqual(response.data['results'][0]['release'], 'v4')
   286  
   287      def test_container_errors(self):
   288          url = '/v1/apps'
   289          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   290          self.assertEqual(response.status_code, 201)
   291          app_id = response.data['id']
   292          # create a release so we can scale
   293          app = App.objects.get(id=app_id)
   294          user = User.objects.get(username='autotest')
   295          build = Build.objects.create(owner=user, app=app, image="qwerty")
   296          # create an initial release
   297          Release.objects.create(version=2,
   298                                 owner=user,
   299                                 app=app,
   300                                 config=app.config_set.latest(),
   301                                 build=build)
   302          url = "/v1/apps/{app_id}/scale".format(**locals())
   303          body = {'web': 'not_an_int'}
   304          response = self.client.post(url, json.dumps(body), content_type='application/json',
   305                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   306          self.assertContains(response, 'Invalid scaling format', status_code=400)
   307          body = {'invalid': 1}
   308          response = self.client.post(url, json.dumps(body), content_type='application/json',
   309                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   310          self.assertContains(response, 'Container type invalid', status_code=400)
   311  
   312      def test_container_str(self):
   313          """Test the text representation of a container."""
   314          url = '/v1/apps'
   315          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   316          self.assertEqual(response.status_code, 201)
   317          app_id = response.data['id']
   318          # post a new build
   319          url = "/v1/apps/{app_id}/builds".format(**locals())
   320          body = {'image': 'autotest/example', 'sha': 'a'*40,
   321                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   322          response = self.client.post(url, json.dumps(body), content_type='application/json',
   323                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   324          self.assertEqual(response.status_code, 201)
   325          # scale up
   326          url = "/v1/apps/{app_id}/scale".format(**locals())
   327          body = {'web': 4, 'worker': 2}
   328          response = self.client.post(url, json.dumps(body), content_type='application/json',
   329                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   330          self.assertEqual(response.status_code, 204)
   331          # should start with zero
   332          url = "/v1/apps/{app_id}/containers".format(**locals())
   333          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   334          self.assertEqual(response.status_code, 200)
   335          self.assertEqual(len(response.data['results']), 6)
   336          uuid = response.data['results'][0]['uuid']
   337          container = Container.objects.get(uuid=uuid)
   338          self.assertEqual(container.short_name(),
   339                           "{}.{}.{}".format(container.app, container.type, container.num))
   340          self.assertEqual(str(container),
   341                           "{}.{}.{}".format(container.app, container.type, container.num))
   342  
   343      def test_container_command_format(self):
   344          # regression test for https://github.com/deis/deis/pull/1285
   345          url = '/v1/apps'
   346          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   347          self.assertEqual(response.status_code, 201)
   348          app_id = response.data['id']
   349          # post a new build
   350          url = "/v1/apps/{app_id}/builds".format(**locals())
   351          body = {'image': 'autotest/example', 'sha': 'a'*40,
   352                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   353          response = self.client.post(url, json.dumps(body), content_type='application/json',
   354                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   355          self.assertEqual(response.status_code, 201)
   356          # scale up
   357          url = "/v1/apps/{app_id}/scale".format(**locals())
   358          body = {'web': 1}
   359          response = self.client.post(url, json.dumps(body), content_type='application/json',
   360                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   361          self.assertEqual(response.status_code, 204)
   362          url = "/v1/apps/{app_id}/containers".format(**locals())
   363          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   364          # verify that the container._command property got formatted
   365          self.assertEqual(response.status_code, 200)
   366          self.assertEqual(len(response.data['results']), 1)
   367          uuid = response.data['results'][0]['uuid']
   368          container = Container.objects.get(uuid=uuid)
   369          self.assertNotIn('{c_type}', container._command)
   370  
   371      def test_container_scale_errors(self):
   372          url = '/v1/apps'
   373          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   374          self.assertEqual(response.status_code, 201)
   375          app_id = response.data['id']
   376          # should start with zero
   377          url = "/v1/apps/{app_id}/containers".format(**locals())
   378          response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   379          self.assertEqual(response.status_code, 200)
   380          self.assertEqual(len(response.data['results']), 0)
   381          # post a new build
   382          url = "/v1/apps/{app_id}/builds".format(**locals())
   383          body = {'image': 'autotest/example', 'sha': 'a'*40,
   384                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   385          response = self.client.post(url, json.dumps(body), content_type='application/json',
   386                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   387          self.assertEqual(response.status_code, 201)
   388          # scale to a negative number
   389          url = "/v1/apps/{app_id}/scale".format(**locals())
   390          body = {'web': -1}
   391          response = self.client.post(url, json.dumps(body), content_type='application/json',
   392                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   393          self.assertEqual(response.status_code, 400)
   394          # scale to something other than a number
   395          url = "/v1/apps/{app_id}/scale".format(**locals())
   396          body = {'web': 'one'}
   397          response = self.client.post(url, json.dumps(body), content_type='application/json',
   398                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   399          self.assertEqual(response.status_code, 400)
   400          # scale to something other than a number
   401          url = "/v1/apps/{app_id}/scale".format(**locals())
   402          body = {'web': [1]}
   403          response = self.client.post(url, json.dumps(body), content_type='application/json',
   404                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   405          self.assertEqual(response.status_code, 400)
   406          # scale up to an integer as a sanity check
   407          url = "/v1/apps/{app_id}/scale".format(**locals())
   408          body = {'web': 1}
   409          response = self.client.post(url, json.dumps(body), content_type='application/json',
   410                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   411          self.assertEqual(response.status_code, 204)
   412  
   413      def test_admin_can_manage_other_containers(self):
   414          """If a non-admin user creates a container, an administrator should be able to
   415          manage it.
   416          """
   417          user = User.objects.get(username='autotest2')
   418          token = Token.objects.get(user=user).key
   419          url = '/v1/apps'
   420          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(token))
   421          self.assertEqual(response.status_code, 201)
   422          app_id = response.data['id']
   423          # post a new build
   424          url = "/v1/apps/{app_id}/builds".format(**locals())
   425          body = {'image': 'autotest/example', 'sha': 'a'*40,
   426                  'procfile': json.dumps({'web': 'node server.js', 'worker': 'node worker.js'})}
   427          response = self.client.post(url, json.dumps(body), content_type='application/json',
   428                                      HTTP_AUTHORIZATION='token {}'.format(token))
   429          self.assertEqual(response.status_code, 201)
   430          # login as admin, scale up
   431          url = "/v1/apps/{app_id}/scale".format(**locals())
   432          body = {'web': 4, 'worker': 2}
   433          response = self.client.post(url, json.dumps(body), content_type='application/json',
   434                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   435          self.assertEqual(response.status_code, 204)
   436  
   437      def test_scale_without_build_should_error(self):
   438          """A user should not be able to scale processes unless a build is present."""
   439          app_id = 'autotest'
   440          url = '/v1/apps'
   441          body = {'cluster': 'autotest', 'id': app_id}
   442          response = self.client.post(url, json.dumps(body), content_type='application/json',
   443                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   444          url = '/v1/apps/{app_id}/scale'.format(**locals())
   445          body = {'web': '1'}
   446          response = self.client.post(url, json.dumps(body), content_type='application/json',
   447                                      HTTP_AUTHORIZATION='token {}'.format(self.token))
   448          self.assertEqual(response.status_code, 400)
   449          self.assertEqual(response.data, "No build associated with this release")
   450  
   451      def test_command_good(self):
   452          """Test the default command for each container workflow"""
   453          url = '/v1/apps'
   454          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   455          self.assertEqual(response.status_code, 201)
   456          app_id = response.data['id']
   457          app = App.objects.get(id=app_id)
   458          user = User.objects.get(username='autotest')
   459          # Heroku Buildpack app
   460          build = Build.objects.create(owner=user,
   461                                       app=app,
   462                                       image="qwerty",
   463                                       procfile={'web': 'node server.js',
   464                                                 'worker': 'node worker.js'},
   465                                       sha='african-swallow',
   466                                       dockerfile='')
   467          # create an initial release
   468          release = Release.objects.create(version=2,
   469                                           owner=user,
   470                                           app=app,
   471                                           config=app.config_set.latest(),
   472                                           build=build)
   473          # create a container
   474          c = Container.objects.create(owner=user,
   475                                       app=app,
   476                                       release=release,
   477                                       type='web',
   478                                       num=1)
   479          # use `start web` for backwards compatibility with slugrunner
   480          self.assertEqual(c._command, 'start web')
   481          c.type = 'worker'
   482          self.assertEqual(c._command, 'start worker')
   483          # switch to docker image app
   484          build.sha = None
   485          c.type = 'web'
   486          self.assertEqual(c._command, "bash -c 'node server.js'")
   487          # switch to dockerfile app
   488          build.sha = 'european-swallow'
   489          build.dockerfile = 'dockerdockerdocker'
   490          self.assertEqual(c._command, "bash -c 'node server.js'")
   491          c.type = 'cmd'
   492          self.assertEqual(c._command, '')
   493          # ensure we can override the cmd process type in a Procfile
   494          build.procfile['cmd'] = 'node server.js'
   495          self.assertEqual(c._command, "bash -c 'node server.js'")
   496          c.type = 'worker'
   497          self.assertEqual(c._command, "bash -c 'node worker.js'")
   498          c.release.build.procfile = None
   499          # for backwards compatibility if no Procfile is supplied
   500          self.assertEqual(c._command, 'start worker')
   501  
   502      def test_run_command_good(self):
   503          """Test the run command for each container workflow"""
   504          url = '/v1/apps'
   505          response = self.client.post(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
   506          self.assertEqual(response.status_code, 201)
   507          app_id = response.data['id']
   508          app = App.objects.get(id=app_id)
   509          user = User.objects.get(username='autotest')
   510          # dockerfile + procfile worflow
   511          build = Build.objects.create(owner=user,
   512                                       app=app,
   513                                       image="qwerty",
   514                                       procfile={'web': 'node server.js',
   515                                                 'worker': 'node worker.js'},
   516                                       dockerfile='foo',
   517                                       sha='somereallylongsha')
   518          # create an initial release
   519          release = Release.objects.create(version=2,
   520                                           owner=user,
   521                                           app=app,
   522                                           config=app.config_set.latest(),
   523                                           build=build)
   524          # create a container
   525          c = Container.objects.create(owner=user,
   526                                       app=app,
   527                                       release=release,
   528                                       type='web',
   529                                       num=1)
   530          rc, output = c.run('echo hi')
   531          self.assertEqual(rc, 0)
   532          self.assertEqual(json.loads(output)['entrypoint'], '/bin/bash')
   533          # docker image workflow
   534          build.dockerfile = None
   535          build.sha = None
   536          rc, output = c.run('echo hi')
   537          self.assertEqual(json.loads(output)['entrypoint'], '/bin/bash')
   538          # procfile workflow
   539          build.sha = 'somereallylongsha'
   540          rc, output = c.run('echo hi')
   541          self.assertEqual(json.loads(output)['entrypoint'], '/runner/init')