diff --git a/src/documents/tests/test_api_status.py b/src/documents/tests/test_api_status.py index 6f200e54f..a8a21a28c 100644 --- a/src/documents/tests/test_api_status.py +++ b/src/documents/tests/test_api_status.py @@ -539,3 +539,28 @@ class TestSystemStatus(APITestCase): self.assertEqual(response.data["tasks"]["summary"]["success_count"], 1) self.assertEqual(response.data["tasks"]["summary"]["failure_count"], 1) self.assertEqual(response.data["tasks"]["summary"]["pending_count"], 1) + + def test_system_status_reports_database_error(self) -> None: + """ + GIVEN: + - Reading the migration state fails + WHEN: + - The system status is requested + THEN: + - The response reports the database error rather than a server error + """ + self.client.force_login(self.user) + with mock.patch( + "documents.views.MigrationLoader", + side_effect=Exception("database is down"), + ): + response = self.client.get(self.ENDPOINT) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + database = response.data["database"] + self.assertEqual(database["status"], "ERROR") + self.assertIsNotNone(database["error"]) + self.assertEqual( + database["migration_status"], + {"latest_migration": None, "unapplied_migrations": []}, + ) diff --git a/src/documents/views.py b/src/documents/views.py index 5e17c67cb..5508fb634 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -5267,7 +5267,9 @@ class CustomFieldViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[Custom "migration_status": inline_serializer( name="MigrationStatus", fields={ - "latest_migration": serializers.CharField(), + "latest_migration": serializers.CharField( + allow_null=True, + ), "unapplied_migrations": serializers.ListSerializer( child=serializers.CharField(), ), @@ -5342,6 +5344,8 @@ class SystemStatusView(PassUserMixin): db_conn = connections["default"] db_url = str(db_conn.settings_dict["NAME"]) db_error = None + all_migrations: list[str] = [] + applied_migrations: list[str] = [] try: db_conn.ensure_connection() @@ -5352,7 +5356,7 @@ class SystemStatusView(PassUserMixin): f"{m.app}.{m.name}" for m in MigrationRecorder.Migration.objects.all().order_by("id") ] - except Exception as e: # pragma: no cover + except Exception as e: applied_migrations = [] db_status = "ERROR" logger.exception( @@ -5548,7 +5552,9 @@ class SystemStatusView(PassUserMixin): "status": db_status, "error": db_error, "migration_status": { - "latest_migration": applied_migrations[-1], + "latest_migration": ( + applied_migrations[-1] if applied_migrations else None + ), "unapplied_migrations": [ m for m in all_migrations if m not in applied_migrations ],