Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/containerbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ on:
- unstable
- hotfixes
- master
- search-recommendations
tags:
- 'v*'
pull_request:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,26 +67,28 @@ def test_recommend_success(self, mock_load_recommendations):
def test_recommend_invalid_data_empty_data(self):
self.client.force_authenticate(user=self.admin_user)

error_message = "Invalid request data. Please check the required fields."
invalid_data = {}
response = self.client.post(reverse("recommendations"), data=invalid_data,
format="json")
self.assertEqual(response.status_code, 400)
self.assertIn("topics", response.json()['error'])
self.assertIn(error_message, response.json()['error'])

def test_recommend_invalid_data_wrong_topic_data(self):
self.client.force_authenticate(user=self.admin_user)

error_message = "Invalid request data. Please check the required fields."
invalid_data = {'topics': [{'ramdon_field': "random_value"}]}
response = self.client.post(reverse("recommendations"), data=invalid_data,
format="json")
self.assertEqual(response.status_code, 400)
self.assertIn("ramdon_field", response.json()['error'])
self.assertEqual(error_message, response.json()['error'])

@patch("contentcuration.utils.automation_manager.AutomationManager.load_recommendations")
def test_recommendation_invalid_data_formats(self, mock_load_recommendations):
self.client.force_authenticate(user=self.admin_user)

error_message = "Invalid topic format"
error_message = "Invalid input provided."
mock_load_recommendations.side_effect = ValueError(error_message)

response = self.client.post(reverse("recommendations"), data=self.topics,
Expand All @@ -100,27 +102,25 @@ def test_recommendation_invalid_data_formats(self, mock_load_recommendations):
def test_recommendation_service_unavailable(self, mock_load_recommendations):
self.client.force_authenticate(user=self.admin_user)

error_message = "Connection error"
error_message = "Recommendation service unavailable"
mock_load_recommendations.side_effect = ConnectionError(error_message)

response = self.client.post(reverse("recommendations"), data=self.topics,
format="json")

self.assertEqual(response.status_code, 503)
self.assertEqual(response.json(),
{"error": f"Recommendation service unavailable: {error_message}"})
self.assertEqual(response.json(), {"error": error_message})
mock_load_recommendations.assert_called_once()

@patch("contentcuration.utils.automation_manager.AutomationManager.load_recommendations")
def test_recommendation_generic_error(self, mock_load_recommendations):
self.client.force_authenticate(user=self.admin_user)

error_message = "Unexpected internal error"
error_message = "Unable to load recommendations"
mock_load_recommendations.side_effect = RuntimeError(error_message)
response = self.client.post(reverse("recommendations"), data=self.topics,
format="json")

self.assertEqual(response.status_code, 500)
self.assertEqual(response.content.decode(),
f"Unable to load recommendations: {error_message}")
self.assertEqual(response.content.decode(), error_message)
mock_load_recommendations.assert_called_once()
16 changes: 12 additions & 4 deletions contentcuration/contentcuration/viewsets/recommendation.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
from http import HTTPStatus

import jsonschema
Expand All @@ -10,6 +11,8 @@
from contentcuration.utils.automation_manager import AutomationManager
from contentcuration.viewsets.user import IsAIFeatureEnabledForUser

logger = logging.getLogger(__name__)


class RecommendationView(APIView):

Expand All @@ -27,15 +30,20 @@ def post(self, request):

embed_topics_request.validate(request_data)
except jsonschema.ValidationError as e:
return JsonResponse({"error": f"Required fields missing: {str(e)}"}, status=HTTPStatus.BAD_REQUEST)
logger.error("Schema validation error: %s", str(e))
return JsonResponse({"error": "Invalid request data. Please check the required fields."}, status=HTTPStatus.BAD_REQUEST)

try:
recommendations = self.manager.load_recommendations(request_data, override_threshold)
return JsonResponse(data=recommendations, safe=False)
except (ValueError, TypeError) as e:
return JsonResponse({"error": str(e)}, status=HTTPStatus.BAD_REQUEST)
logger.error("Validation error occurred: %s", str(e), exc_info=True)
return JsonResponse({"error": "Invalid input provided."},
status=HTTPStatus.BAD_REQUEST)
except ConnectionError as e:
return JsonResponse({"error": f"Recommendation service unavailable: {str(e)}"},
logger.error("Connection error occurred: %s", str(e), exc_info=True)
return JsonResponse({"error": "Recommendation service unavailable"},
status=HTTPStatus.SERVICE_UNAVAILABLE)
except Exception as e:
return HttpResponseServerError(f"Unable to load recommendations: {str(e)}")
logger.error("Unexpected error occurred: %s", str(e), exc_info=True)
return HttpResponseServerError("Unable to load recommendations")
1 change: 0 additions & 1 deletion requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@ python-dateutil>=2.8.1
jsonschema>=3.2.0
django-celery-results
packaging>=21.0
pgvector