Skip to content

Commit df10ebb

Browse files
committed
chore(tests): improve coverage by triggering KubeExceptions (and other types)
1 parent 3c6ea6c commit df10ebb

7 files changed

Lines changed: 299 additions & 37 deletions

File tree

rootfs/api/tests/test_app.py

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from rest_framework.authtoken.models import Token
1515

1616
from api.models import App
17+
from scheduler import KubeException
1718

1819
from . import adapter
1920
import requests_mock
@@ -266,9 +267,7 @@ def test_run(self, mock_requests):
266267
A user should be able to run a one off command
267268
"""
268269
app_id = 'autotest'
269-
url = '/v2/apps'
270-
body = {'id': app_id}
271-
response = self.client.post(url, body)
270+
response = self.client.post('/v2/apps', {'id': app_id})
272271

273272
# create build
274273
body = {'image': 'autotest/example'}
@@ -284,6 +283,25 @@ def test_run(self, mock_requests):
284283
self.assertEqual(response.data['rc'], 0)
285284
self.assertEqual(response.data['output'], 'mock')
286285

286+
def test_run_failure(self, mock_requests):
287+
"""Raise a KubeException via scheduler.run"""
288+
app_id = 'autotest'
289+
response = self.client.post('/v2/apps', {'id': app_id})
290+
291+
# create build
292+
body = {'image': 'autotest/example'}
293+
url = '/v2/apps/{app_id}/builds'.format(**locals())
294+
response = self.client.post(url, body)
295+
self.assertEqual(response.status_code, 201)
296+
297+
with mock.patch('scheduler.KubeHTTPClient.run') as kube_run:
298+
kube_run.side_effect = KubeException('boom!')
299+
# run command
300+
url = '/v2/apps/{}/run'.format(app_id)
301+
body = {'command': 'ls -al'}
302+
response = self.client.post(url, body)
303+
self.assertEqual(response.status_code, 503)
304+
287305
def test_unauthorized_user_cannot_see_app(self, mock_requests):
288306
"""
289307
An unauthorized user should not be able to access an app's resources.
@@ -384,6 +402,30 @@ def test_app_exists_in_kubernetes(self, mock_requests):
384402
status_code=409
385403
)
386404

405+
def test_app_create_failure_kubernetes_create(self, mock_requests):
406+
"""
407+
Create an app but have scheduler.create fail with an exception
408+
"""
409+
with mock.patch('scheduler.KubeHTTPClient.create') as mock_kube:
410+
mock_kube.side_effect = KubeException('Boom!')
411+
response = self.client.post('/v2/apps', {'id': 'test-kube'})
412+
self.assertEqual(response.status_code, 503)
413+
414+
def test_app_delete_failure_kubernetes_destroy(self, mock_requests):
415+
"""
416+
Create an app and then delete but have scheduler.destroy
417+
fail with an exception
418+
"""
419+
# create
420+
response = self.client.post('/v2/apps', {'id': 'test'})
421+
self.assertEqual(response.status_code, 201)
422+
423+
with mock.patch('scheduler.KubeHTTPClient.destroy') as mock_kube:
424+
# delete
425+
mock_kube.side_effect = KubeException('Boom!')
426+
response = self.client.delete('/v2/apps/test')
427+
self.assertEqual(response.status_code, 503)
428+
387429
def test_app_verify_application_health_success(self, mock_requests):
388430
"""
389431
Create an application which in turn causes a health check to run against

rootfs/api/tests/test_build.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
from rest_framework.authtoken.models import Token
1616

1717
from api.models import Build
18+
from registry.dockerclient import RegistryException
19+
from scheduler import KubeException
1820

1921
from . import adapter
2022
import requests_mock
@@ -346,3 +348,78 @@ def test_build_image_in_registry(self, mock_requests):
346348
release = build.app.release_set.latest()
347349
# Registry host + port is internally stripped off
348350
self.assertEqual(release.image, 'autotest/example')
351+
352+
def test_build_image_in_registry_with_auth(self, mock_requests):
353+
"""add authentication to the build"""
354+
self.client.post('/v2/apps', {'id': 'test'})
355+
356+
# post an image as a build using registry hostname
357+
url = "/v2/apps/test/builds"
358+
image = 'autotest/example'
359+
response = self.client.post(url, {'image': image})
360+
self.assertEqual(response.status_code, 201)
361+
362+
# set some registry information
363+
url = '/v2/apps/test/config'
364+
body = {'registry': json.dumps({'username': 'bob', 'password': 'zoomzoom'})}
365+
response = self.client.post(url, body)
366+
self.assertEqual(response.status_code, 201)
367+
368+
def test_release_create_failure(self, mock_requests):
369+
"""
370+
Cause an Exception in app.deploy to cause a release.delete in build.create
371+
"""
372+
body = {'id': 'test'}
373+
self.client.post('/v2/apps', body)
374+
375+
# deploy app to get a build
376+
url = "/v2/apps/test/builds"
377+
body = {'image': 'autotest/example'}
378+
response = self.client.post(url, body)
379+
self.assertEqual(response.status_code, 201)
380+
self.assertEqual(response.data['image'], body['image'])
381+
382+
with mock.patch('api.models.App.deploy') as mock_deploy:
383+
mock_deploy.side_effect = Exception('Boom!')
384+
385+
url = "/v2/apps/test/builds"
386+
body = {'image': 'autotest/example'}
387+
response = self.client.post(url, body)
388+
self.assertEqual(response.status_code, 400)
389+
390+
def test_release_registry_create_failure(self, mock_requests):
391+
"""
392+
Cause a RegistryException in app.deploy to cause a release.delete in build.create
393+
"""
394+
body = {'id': 'test'}
395+
self.client.post('/v2/apps', body)
396+
397+
# deploy app to get a build
398+
url = "/v2/apps/test/builds"
399+
body = {'image': 'autotest/example'}
400+
response = self.client.post(url, body)
401+
self.assertEqual(response.status_code, 201)
402+
self.assertEqual(response.data['image'], body['image'])
403+
404+
with mock.patch('api.models.Release.publish') as mock_registry:
405+
mock_registry.side_effect = RegistryException('Boom!')
406+
407+
url = "/v2/apps/test/builds"
408+
body = {'image': 'autotest/example'}
409+
response = self.client.post(url, body)
410+
self.assertEqual(response.status_code, 400)
411+
412+
def test_build_deploy_kube_failure(self, mock_requests):
413+
"""
414+
Cause an Exception in scheduler.deploy
415+
"""
416+
body = {'id': 'test'}
417+
self.client.post('/v2/apps', body)
418+
419+
with mock.patch('scheduler.KubeHTTPClient.deploy') as mock_deploy:
420+
mock_deploy.side_effect = KubeException('Boom!')
421+
422+
url = "/v2/apps/test/builds"
423+
body = {'image': 'autotest/example'}
424+
response = self.client.post(url, body)
425+
self.assertEqual(response.status_code, 400)

rootfs/api/tests/test_certificate_use_case_1.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,18 @@ def test_get_certificate_screens_data(self):
110110
for key, value in list(expected.items()):
111111
self.assertEqual(response.data[key], value, key)
112112

113-
# detach domain to certificate
113+
# detach domain from a certificate
114114
response = self.client.delete(
115115
'{}/{}/domain/{}'.format(self.url, self.name, self.domain)
116116
)
117117
self.assertEqual(response.status_code, 204)
118118

119+
# detach a domain that does not exist from a certificate
120+
response = self.client.delete(
121+
'{}/{}/domain/{}'.format(self.url, self.name, 'i-am-fake.com')
122+
)
123+
self.assertEqual(response.status_code, 404)
124+
119125
# Assert data
120126
response = self.client.get('{}/{}'.format(self.url, self.name))
121127
self.assertEqual(response.status_code, 200)

rootfs/api/tests/test_config.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,29 @@ def test_valid_config_keys(self, mock_requests):
237237
self.assertEqual(resp.status_code, 201)
238238
self.assertIn(k, resp.data['values'])
239239

240+
def test_config_deploy_failure(self, mock_requests):
241+
"""
242+
Cause an Exception in app.deploy to cause a release.delete
243+
"""
244+
url = '/v2/apps'
245+
response = self.client.post(url)
246+
self.assertEqual(response.status_code, 201)
247+
app_id = response.data['id']
248+
249+
# deploy app to get a build
250+
url = "/v2/apps/{}/builds".format(app_id)
251+
body = {'image': 'autotest/example'}
252+
response = self.client.post(url, body)
253+
self.assertEqual(response.status_code, 201)
254+
self.assertEqual(response.data['image'], body['image'])
255+
256+
with mock.patch('api.models.App.deploy') as mock_deploy:
257+
mock_deploy.side_effect = Exception('Boom!')
258+
url = '/v2/apps/{app_id}/config'.format(**locals())
259+
body = {'values': json.dumps({'test': "testvalue"})}
260+
resp = self.client.post(url, body)
261+
self.assertEqual(resp.status_code, 400)
262+
240263
def test_invalid_config_keys(self, mock_requests):
241264
"""Test that invalid config keys are rejected.
242265
"""
@@ -548,6 +571,13 @@ def test_tags(self, mock_requests):
548571
body = {'tags': json.dumps({'host.name.com/,not.valid': 'valid'})}
549572
response = self.client.post(url, body)
550573
self.assertEqual(response.status_code, 400)
574+
long_tag = 'a' * 300
575+
body = {'tags': json.dumps({'{}/not.valid'.format(long_tag): 'valid'})}
576+
response = self.client.post(url, body)
577+
self.assertEqual(response.status_code, 400)
578+
body = {'tags': json.dumps({'this&foo.com/not.valid': 'valid'})}
579+
response = self.client.post(url, body)
580+
self.assertEqual(response.status_code, 400)
551581

552582
# disallow put/patch/delete
553583
response = self.client.put(url)
@@ -619,6 +649,12 @@ def test_registry(self, mock_requests):
619649
self.assertNotEqual(registry3['uuid'], registry4['uuid'])
620650
self.assertNotIn('password', json.dumps(response.data['registry']))
621651

652+
# bad registry key values
653+
body = {'registry': json.dumps({'pa$$w0rd': 'woop'})}
654+
response = self.client.post(url, body)
655+
response = self.client.post(url, body)
656+
self.assertEqual(response.status_code, 400)
657+
622658
# disallow put/patch/delete
623659
response = self.client.put(url)
624660
self.assertEqual(response.status_code, 405)

0 commit comments

Comments
 (0)