Skip to content

Commit e383586

Browse files
committed
fix(app): response object was not accessible if app verification threw request exception
Fixes #682
1 parent 5821726 commit e383586

2 files changed

Lines changed: 102 additions & 1 deletion

File tree

rootfs/api/models/app.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,11 +461,15 @@ def verify_application_health(self, **kwargs):
461461
# Give the router max of 10 tries or max 30 seconds to become healthy
462462
# Uses time module to account for the timout value of 3 seconds
463463
start = time.time()
464+
failed = False
464465
for _ in range(10):
465466
try:
466467
# http://docs.python-requests.org/en/master/user/advanced/#timeouts
467468
response = session.get(url, timeout=req_timeout)
469+
failed = False
468470
except requests.exceptions.RequestException:
471+
# In case of a failure where response object is not available
472+
failed = True
469473
# We are fine with timeouts and request problems, lets keep trying
470474
time.sleep(1) # just a bit of a buffer
471475
continue
@@ -482,7 +486,7 @@ def verify_application_health(self, **kwargs):
482486
time.sleep(1)
483487

484488
# Endpoint did not report healthy in time
485-
if response.status_code == 404:
489+
if ('response' in locals() and response.status_code == 404) or failed:
486490
delta = time.time() - start
487491
self.log(
488492
'Router was not ready to serve traffic to process type {} in time, waited {} seconds'.format(app_type, delta), # noqa

rootfs/api/tests/test_app.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from unittest import mock
88
import requests
99

10+
from django.conf import settings
1011
from django.contrib.auth.models import User
1112
from django.core.cache import cache
1213
from rest_framework.test import APITestCase
@@ -27,6 +28,7 @@ def _mock_run(*args, **kwargs):
2728

2829

2930
@requests_mock.Mocker(real_http=True, adapter=adapter)
31+
@mock.patch('api.models.release.publish_release', lambda *args: None)
3032
class AppTest(APITestCase):
3133
"""Tests creation of applications"""
3234

@@ -382,6 +384,101 @@ def test_app_exists_in_kubernetes(self, mock_requests):
382384
status_code=409
383385
)
384386

387+
def test_app_verify_application_health_success(self, mock_requests):
388+
"""
389+
Create an application which in turn causes a health check to run against
390+
the router. Make it succeed on the 6th try
391+
"""
392+
responses = [
393+
{'text': 'Not Found', 'status_code': 404},
394+
{'text': 'Not Found', 'status_code': 404},
395+
{'text': 'Not Found', 'status_code': 404},
396+
{'text': 'Not Found', 'status_code': 404},
397+
{'text': 'Not Found', 'status_code': 404},
398+
{'text': 'OK', 'status_code': 200}
399+
]
400+
hostname = 'http://{}:{}/'.format(settings.ROUTER_HOST, settings.ROUTER_PORT)
401+
mr = mock_requests.register_uri('GET', hostname, responses)
402+
403+
# create app
404+
body = {'id': 'myid'}
405+
response = self.client.post('/v2/apps', body)
406+
self.assertEqual(response.status_code, 201)
407+
408+
# deploy app to get verification
409+
url = "/v2/apps/myid/builds"
410+
body = {'image': 'autotest/example'}
411+
response = self.client.post(url, body)
412+
self.assertEqual(response.status_code, 201)
413+
self.assertEqual(response.data['image'], body['image'])
414+
415+
self.assertEqual(mr.called, True)
416+
self.assertEqual(mr.call_count, 6)
417+
418+
def test_app_verify_application_health_failure_404(self, mock_requests):
419+
"""
420+
Create an application which in turn causes a health check to run against
421+
the router. Make it fail with a 404 after 10 tries
422+
"""
423+
# function tries to hit router 10 times
424+
responses = [
425+
{'text': 'Not Found', 'status_code': 404},
426+
{'text': 'Not Found', 'status_code': 404},
427+
{'text': 'Not Found', 'status_code': 404},
428+
{'text': 'Not Found', 'status_code': 404},
429+
{'text': 'Not Found', 'status_code': 404},
430+
{'text': 'Not Found', 'status_code': 404},
431+
{'text': 'Not Found', 'status_code': 404},
432+
{'text': 'Not Found', 'status_code': 404},
433+
{'text': 'Not Found', 'status_code': 404},
434+
{'text': 'Not Found', 'status_code': 404},
435+
]
436+
hostname = 'http://{}:{}/'.format(settings.ROUTER_HOST, settings.ROUTER_PORT)
437+
mr = mock_requests.register_uri('GET', hostname, responses)
438+
439+
# create app
440+
body = {'id': 'myid'}
441+
response = self.client.post('/v2/apps', body)
442+
self.assertEqual(response.status_code, 201)
443+
444+
# deploy app to get verification
445+
url = "/v2/apps/myid/builds"
446+
body = {'image': 'autotest/example'}
447+
response = self.client.post(url, body)
448+
self.assertEqual(response.status_code, 201)
449+
self.assertEqual(response.data['image'], body['image'])
450+
451+
self.assertEqual(mr.called, True)
452+
self.assertEqual(mr.call_count, 10)
453+
454+
def test_app_verify_application_health_failure_exceptions(self, mock_requests):
455+
"""
456+
Create an application which in turn causes a health check to run against
457+
the router. Make it fail with a python-requets exception
458+
"""
459+
def _raise_exception(request, ctx):
460+
raise requests.exceptions.RequestException('Boom!')
461+
462+
# function tries to hit router 10 times
463+
hostname = 'http://{}:{}/'.format(settings.ROUTER_HOST, settings.ROUTER_PORT)
464+
mr = mock_requests.register_uri('GET', hostname, text=_raise_exception)
465+
466+
# create app
467+
body = {'id': 'myid'}
468+
response = self.client.post('/v2/apps', body)
469+
self.assertEqual(response.status_code, 201)
470+
471+
# deploy app to get verification
472+
url = "/v2/apps/myid/builds"
473+
body = {'image': 'autotest/example'}
474+
response = self.client.post(url, body)
475+
self.assertEqual(response.status_code, 201)
476+
self.assertEqual(response.data['image'], body['image'])
477+
478+
# Called 10 times due to the exception
479+
self.assertEqual(mr.called, True)
480+
self.assertEqual(mr.call_count, 10)
481+
385482
FAKE_LOG_DATA = """
386483
2013-08-15 12:41:25 [33454] [INFO] Starting gunicorn 17.5
387484
2013-08-15 12:41:25 [33454] [INFO] Listening at: http://0.0.0.0:5000 (33454)

0 commit comments

Comments
 (0)