diff --git a/onadata/apps/main/tests/test_service_health.py b/onadata/apps/main/tests/test_service_health.py index b9f1767df8..b97dc295f9 100644 --- a/onadata/apps/main/tests/test_service_health.py +++ b/onadata/apps/main/tests/test_service_health.py @@ -1,10 +1,10 @@ import json from django.http import HttpRequest -from django.db.utils import DatabaseError -from mock import patch +from django.test import override_settings from onadata.apps.main.tests.test_base import TestBase from onadata.apps.main.views import service_health +import onadata class TestServiceHealthView(TestBase): @@ -20,21 +20,26 @@ def test_service_health(self): self.assertEqual(resp.status_code, 200) self.assertEqual( - json.loads(resp.content.decode('utf-8')), + json.loads(resp.content.decode("utf-8")), { - 'default-Database': 'OK', - 'Cache-Service': 'OK' - }) + "default-Database": "OK", + "Cache-Service": "OK", + "onadata-version": onadata.__version__, + }, + ) - with patch('onadata.apps.main.views.XForm') as xform_mock: - xform_mock.objects.using().first.side_effect = DatabaseError( - 'Some database error') - resp = service_health(req) + sql_statement_with_error = "SELECT id FROM non_existent_table limit 1;" + with override_settings(CHECK_DB_SQL_STATEMENT=sql_statement_with_error): + resp = service_health(req) self.assertEqual(resp.status_code, 500) + response_json = json.loads(resp.content.decode("utf-8")) + self.assertEqual(response_json["Cache-Service"], "OK") + self.assertEqual(response_json["onadata-version"], onadata.__version__) self.assertEqual( - json.loads(resp.content.decode('utf-8')), - { - 'default-Database': 'Degraded state; Some database error', - 'Cache-Service': 'OK' - }) + response_json["default-Database"][:111], + ( + 'Degraded state; relation "non_existent_table" does not exist' + + f"\nLINE 1: {sql_statement_with_error}" + ), + ) diff --git a/onadata/apps/main/views.py b/onadata/apps/main/views.py index 02b1c1531f..bf4e82cef5 100644 --- a/onadata/apps/main/views.py +++ b/onadata/apps/main/views.py @@ -8,6 +8,7 @@ from datetime import datetime from http import HTTPStatus +from django.db import connections from django.conf import settings from django.contrib import messages from django.contrib.auth import get_user_model @@ -90,6 +91,7 @@ set_profile_data, ) from onadata.libs.utils.viewer_tools import get_enketo_urls, get_form +import onadata # pylint: disable=invalid-name User = get_user_model() @@ -1552,7 +1554,13 @@ def service_health(request): for database in getattr(settings, "DATABASES").keys(): # pylint: disable=broad-except try: - XForm.objects.using(database).first() + with connections[database].cursor() as cursor: + fetch_first_xform_sql = ( + getattr(settings, "CHECK_DB_SQL_STATEMENT", None) + or "SELECT id FROM logger_xform limit 1;" + ) + cursor.execute(fetch_first_xform_sql) + cursor.fetchall() except Exception as e: service_statuses[f"{database}-Database"] = f"Degraded state; {e}" service_degraded = True @@ -1569,6 +1577,11 @@ def service_health(request): else: service_statuses["Cache-Service"] = "OK" + if onadata.__version__: + service_statuses["onadata-version"] = onadata.__version__ + else: + service_statuses["onadata-version"] = "Unable to find onadata version" + return JsonResponse( service_statuses, status=HTTPStatus.INTERNAL_SERVER_ERROR if service_degraded else HTTPStatus.OK, @@ -1592,7 +1605,6 @@ def username_list(request): # pylint: disable=too-few-public-methods class OnaAuthorizationView(AuthorizationView): - """ Overrides the AuthorizationView provided by oauth2_provider and adds the user to the context