From 4461c8fe91ac2816d594491336575b7e4425e2b9 Mon Sep 17 00:00:00 2001 From: Chris Meyers Date: Mon, 22 May 2017 17:32:17 -0400 Subject: [PATCH] more robust insights error handling --- awx/api/views.py | 9 +++-- awx/main/tests/unit/api/test_views.py | 47 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/awx/api/views.py b/awx/api/views.py index 76ca0a0130..b61db39437 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -14,6 +14,7 @@ import subprocess import sys import logging import requests +import urlparse from base64 import b64encode from collections import OrderedDict @@ -2087,9 +2088,11 @@ class HostInsights(GenericAPIView): try: res = self._get_insights(url, username, password) except requests.exceptions.SSLError: - return (dict(error='SSLError while trying to connect to https://access.redhat.com/'), status.HTTP_500_INTERNAL_SERVER_ERROR) + return (dict(error='SSLError while trying to connect to {}'.format(url)), status.HTTP_500_INTERNAL_SERVER_ERROR) except requests.exceptions.Timeout: - return (dict(error='Request to {} timed out'.format(url)), status.HTTP_504_GATEWAY_TIMEOUT) + return (dict(error='Request to {} timed out.'.format(url)), status.HTTP_504_GATEWAY_TIMEOUT) + except requests.exceptions.RequestException as e: + return (dict(error='Unkown exception {} while trying to GET {}'.format(e, url)), status.HTTP_500_INTERNAL_SERVER_ERROR) if res.status_code != 200: return (dict(error='Failed to gather reports and maintenance plans from Insights API. Server responded with {} status code and message {}'.format(res.status_code, res.content)), status.HTTP_500_INTERNAL_SERVER_ERROR) @@ -2097,7 +2100,7 @@ class HostInsights(GenericAPIView): try: return (dict(insights_content=res.json()), status.HTTP_200_OK) except ValueError: - return (None, status.HTTP_204_NO_CONTENT) + return (dict(error='Expected JSON response from Insights but instead got {}'.format(res.content)), status.HTTP_500_INTERNAL_SERVER_ERROR) def get(self, request, *args, **kwargs): host = self.get_object() diff --git a/awx/main/tests/unit/api/test_views.py b/awx/main/tests/unit/api/test_views.py index e4291e50cb..837d202044 100644 --- a/awx/main/tests/unit/api/test_views.py +++ b/awx/main/tests/unit/api/test_views.py @@ -1,5 +1,6 @@ import mock import pytest +import requests from collections import namedtuple @@ -8,6 +9,7 @@ from awx.api.views import ( JobTemplateLabelList, JobTemplateSurveySpec, InventoryInventorySourcesUpdate, + HostInsights, ) @@ -117,3 +119,48 @@ class TestInventoryInventorySourcesUpdate: view = InventoryInventorySourcesUpdate() response = view.post(mock_request) assert response.data == expected + + +class TestHostInsights(): + + @pytest.fixture + def patch_parent(self, mocker): + mocker.patch('awx.api.generics.GenericAPIView') + + @pytest.mark.parametrize("status_code, exception, error, message", [ + (500, requests.exceptions.SSLError, 'SSLError while trying to connect to https://myexample.com/whocares/me/', None,), + (504, requests.exceptions.Timeout, 'Request to https://myexample.com/whocares/me/ timed out.', None,), + (500, requests.exceptions.RequestException, 'booo!', 'Unkown exception booo! while trying to GET https://myexample.com/whocares/me/'), + ]) + def test_get_insights_request_exception(self, patch_parent, mocker, status_code, exception, error, message): + view = HostInsights() + mocker.patch.object(view, '_get_insights', side_effect=exception(error)) + + (msg, code) = view.get_insights('https://myexample.com/whocares/me/', 'ignore', 'ignore') + assert code == status_code + assert msg['error'] == message or error + + def test_get_insights_non_200(self, patch_parent, mocker): + view = HostInsights() + Response = namedtuple('Response', 'status_code content') + mocker.patch.object(view, '_get_insights', return_value=Response(500, 'hello world!')) + + (msg, code) = view.get_insights('https://myexample.com/whocares/me/', 'ignore', 'ignore') + assert msg['error'] == 'Failed to gather reports and maintenance plans from Insights API. Server responded with 500 status code and message hello world!' + + def test_get_insights_malformed_json_content(self, patch_parent, mocker): + view = HostInsights() + + class Response(): + status_code = 200 + content = 'booo!' + + def json(self): + raise ValueError('we do not care what this is') + + mocker.patch.object(view, '_get_insights', return_value=Response()) + + (msg, code) = view.get_insights('https://myexample.com/whocares/me/', 'ignore', 'ignore') + assert msg['error'] == 'Expected JSON response from Insights but instead got booo!' + assert code == 500 +