diff --git a/atdb/taskdatabase/tests/test_filters.py b/atdb/taskdatabase/tests/test_filters.py index 01bb7a7f372f2a58227acc81f71bfe9261ced775..5206de90d5b90d4325460a5e3f71e95e8e7c43db 100644 --- a/atdb/taskdatabase/tests/test_filters.py +++ b/atdb/taskdatabase/tests/test_filters.py @@ -1,10 +1,13 @@ from django.test import TestCase from django.test import RequestFactory +from django.db.models.query import QuerySet from django.contrib.sessions.middleware import SessionMiddleware +from unittest.mock import patch, MagicMock + from taskdatabase.models import Task, Workflow, Activity from taskdatabase.views import get_filtered_tasks -class FiltersTest(TestCase): +class TestFilters(TestCase): def setUp(self): self.workflow_requantisation = Workflow(id=22, workflow_uri="psrfits_requantisation") self.workflow_requantisation.save() @@ -18,6 +21,13 @@ class FiltersTest(TestCase): self.task4 = Task.objects.create(sas_id=66666, status='scrubbed', workflow=self.workflow_requantisation, activity = self.activity_66666) self.task5 = Task.objects.create(sas_id=66666, status='archived_failed', workflow=self.workflow_requantisation, activity = self.activity_66666) + def _set_up_session(self, request): + """Helper function to set up session for the request""" + middleware = SessionMiddleware(get_response=lambda r: None) + middleware.process_request(request) + #request.session.update(self.session_data) + request.session.save() + def test_without_filter(self): count = 0 for task in Task.objects.all(): @@ -26,12 +36,67 @@ class FiltersTest(TestCase): self.assertEqual(count,5) def test_with_ingest_filter(self): + # Arrange # create a request object request = RequestFactory().get('/atdb/ingest') # this simulates the 'Queue (scrubbed)' filter on the ingest page request.session = {'ingest_filter': 'scrubbed'} + # Act # after aggregating per sas_id, 2 objects with status 'scrubbed' remain tasks = get_filtered_tasks(request, None, "sas_id") + + # Assert self.assertEqual(tasks.count(), 2) + + + def test_with_task_status_filter(self): + # Arrange + # create a request object + request = RequestFactory().get('/atdb') + request.session = {'task_filter': 'scrubbed'} + + # Act + tasks = get_filtered_tasks(request, None, None) + + # Assert + self.assertEqual(tasks.count(), 3) + + def test_with_filtered_task_on_session(self): + """ + test with pre_filtered tasks on the session + """ + + # Arrange + # create a request object + request = RequestFactory().get('/atdb') + + filtered_tasks_as_list = [self.task1.id,self.task2.id,self.task3.id] + request.session = {'filtered_tasks_as_list': filtered_tasks_as_list} + + # Act + tasks = get_filtered_tasks(request, None, None) + + # Assert + self.assertEqual(tasks.count(), 3) + + + def test_with_prefiltered_task_as_parameter(self): + """ + test with pre_filtered tasks as function parameter + """ + + # Arrange + # create a request object + request = RequestFactory().get('/atdb') + self._set_up_session(request) + pre_filtered_tasks = Task.objects.all() + + # Act + # after aggregating per sas_id, 2 objects with status 'scrubbed' remain + tasks = get_filtered_tasks(request, pre_filtered_tasks, None) + + # Assert + self.assertEqual(tasks.count(), 5) + diff --git a/atdb/taskdatabase/tests/test_views.py b/atdb/taskdatabase/tests/test_views.py index 33595035b497ae7bb05275c38bfdcf020748597c..f27922bc6fa40db79a3c79c13a9b771f2eec4f90 100644 --- a/atdb/taskdatabase/tests/test_views.py +++ b/atdb/taskdatabase/tests/test_views.py @@ -3,10 +3,13 @@ from django.urls import reverse from django.contrib.auth.models import User from django.contrib.sessions.middleware import SessionMiddleware +from django.contrib.messages.storage.fallback import FallbackStorage from taskdatabase.models import Task, Workflow, LatestMonitor from taskdatabase.views import SortTasks, TaskMultiStatus, TaskMultiHold, TaskMultiPurge, Hold, HoldQuery, PurgeQuery, \ - TaskSetStatus, TaskRetry, TaskDiscard, TaskDiscardSasId, ServiceHoldResume, TaskValidateTask,TaskValidateSasId + TaskSetStatus, TaskRetry, TaskDiscard, TaskDiscardSasId, ServiceHoldResume, TaskValidateTask,TaskValidateSasId,\ + convert_query_params_to_url, GetSizeView, ShowTaskQuality, AnnotateQualitySasId, AnnotateQualityTaskId, \ + ClearAnnotationsSasID from django.db.models.query import QuerySet from unittest.mock import patch, MagicMock @@ -21,13 +24,15 @@ class TestViews(TestCase): # Create a test task self.task1 = Task.objects.create(sas_id=123, status='defined', workflow=workflow_requantisation, - remarks = {"discard_reason" : "no longer needed"}) + remarks = {"discard_reason" : "no longer needed", + "quality_sasid" : "initial remark for sas_id", + "quality_taskid" : "initial remark for task_id"}) self.task2 = Task.objects.create(sas_id=456, status='defined', workflow=workflow_requantisation) self.task3 = Task.objects.create(sas_id=789, status='processed', workflow=workflow_requantisation) self.task4 = Task.objects.create(sas_id=123, status='stored', workflow=workflow_requantisation, remarks = {"discard_reason" : "no longer needed"}) self.task5 = Task.objects.create(sas_id=555, status='stored', workflow=workflow_requantisation, - calculated_qualities = {"per_sasid" : "good"}) + calculated_qualities = {"per_task" : "moderate","per_sasid" : "good"}) self.task6 = Task.objects.create(sas_id=555, status='stored', workflow=workflow_requantisation, calculated_qualities = {"per_sasid" : "good"}) @@ -48,6 +53,14 @@ class TestViews(TestCase): request.session.update(self.session_data) request.session.save() + # Add messages framework to the request + request._messages = FallbackStorage(request) + + def test_basic_conversion(self): + query_params = "<QueryDict: {'filter': ['nv_123'], 'status': ['stored'], 'sas_id': ['12345']}>" + expected_result = "&filter=nv_123&status=stored&sas_id=12345" + self.assertEqual(convert_query_params_to_url(query_params), expected_result) + def test_sort(self): """ test SortTasks @@ -404,3 +417,193 @@ class TestViews(TestCase): self.assertEqual(self.task6.quality, 'good') self.assertEqual(response.status_code, 302) self.assertEqual(response.url, reverse('validation') + '?' + 'page=0') + + + @patch('taskdatabase.views.Task.objects.get') + def test_validate_task(self, mock_get): + """ + test TaskValidateTask + """ + + # Arrange + mock_get.return_value = self.task5 + + request = self.factory.get('/dummy-url') + self._set_up_session(request) + request.user = self.user + + # Act + response = TaskValidateTask(request, self.task5.id, quality='calculated', new_status="validated", page="0") + + # Assert + self.assertEqual(self.task5.quality, 'moderate') + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, reverse('quality') + '?' + 'page=0') + + + @patch('taskdatabase.views.algorithms.get_size') # Mock the get_size function + def test_get_size_view(self, mock_get_size): + # Setup + mock_get_size.return_value = 100 + + request = self.factory.get('/get-size/?status__in=processed,stored&type=to_process') + view = GetSizeView.as_view() + + # Act + response = view(request) + + # Assert + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data, {'total_size': 100}) + mock_get_size.assert_called_once_with(['processed', 'stored'], 'to_process') + + + @patch('taskdatabase.views.algorithms.convert_quality_to_html') + @patch('taskdatabase.views.algorithms.construct_inspectionplots') + def test_show_task_quality_with_valid_id(self, mock_construct_inspectionplots, mock_convert_quality_to_html): + """ + test ShowTaskQuality + """ + + request = self.factory.get('/task_quality/') + self._set_up_session(request) + + # Mocking the algorithms + mock_convert_quality_to_html.return_value = "<p>Quality HTML</p>" + mock_construct_inspectionplots.return_value = "<p>Plots HTML</p>" + + response = ShowTaskQuality(request, id=self.task1.id) + + # Asserts + self.assertEqual(response.status_code, 200) + self.assertIn('Quality HTML', response.content.decode()) + self.assertIn('Plots HTML', response.content.decode()) + self.assertEqual(request.session['task_id'], self.task1.id) + + def test_show_task_quality_with_invalid_id_no_task_in_session(self): + """ + test ShowTaskQuality + """ + request = self.factory.get('/task_quality/') + self._set_up_session(request) + + response = ShowTaskQuality(request, id=0) + + # Asserts + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/atdb/') # Assuming 'index' redirects to '/' + self.assertEqual(len(request._messages), 1) + + + @patch('taskdatabase.views.Task.objects.get') + @patch('taskdatabase.views.Task.objects.filter') + @patch('taskdatabase.views.QualityAnnotationForm.is_valid') + def test_annotate_quality_sasid_post(self, mock_is_valid, mock_filter, mock_get): + """ + test AnnotateQualitySasID (post) + """ + + # Arrange + # Mock the Task.objects.get method to return mock tasks + mock_get.return_value = self.task1 + mock_filter.return_value = [self.task1,self.task4] + mock_is_valid.return_value = True + + post_data = {'annotation': 'quality annotation','return_to_page' : 0} + request = self.factory.post('/dummy-url', data=post_data) + self._set_up_session(request) + + # Act + response = AnnotateQualitySasId(request, self.task1.id) + self.task1.refresh_from_db() + + # Assert + self.assertEqual(self.task1.remarks['quality_sasid'], 'quality annotation') + self.assertEqual(response.status_code, 302) + + @patch('taskdatabase.views.Task.objects.get') + def test_annotate_quality_sasid_get(self, mock_get): + """ + test AnnotateQualitySasID (get) + """ + + # Arrange + # Mock the Task.objects.get method to return mock tasks + mock_get.return_value = self.task1 + + request = self.factory.get('/dummy-url') + self._set_up_session(request) + request.user = self.user + + # Act + response = AnnotateQualitySasId(request, self.task1.id) + + # Assert + self.assertEqual(response.status_code, 200) + self.assertEqual(self.task1.remarks['quality_sasid'], 'initial remark for sas_id') + + @patch('taskdatabase.views.Task.objects.get') + @patch('taskdatabase.views.QualityAnnotationForm.is_valid') + def test_annotate_quality_taskid_post(self, mock_is_valid, mock_get): + """ + test AnnotateQualityTaskId (post) + """ + + # Arrange + # Mock the Task.objects.get method to return mock tasks + mock_get.return_value = self.task1 + mock_is_valid.return_value = True + + post_data = {'annotation': 'quality annotation','return_to_page' : 0} + request = self.factory.post('/dummy-url', data=post_data) + self._set_up_session(request) + + # Act + response = AnnotateQualityTaskId(request, self.task1.id) + self.task1.refresh_from_db() + + # Assert + self.assertEqual(self.task1.remarks['quality_taskid'], 'quality annotation') + self.assertEqual(response.status_code, 302) + + @patch('taskdatabase.views.Task.objects.get') + def test_annotate_quality_taskid_get(self, mock_get): + """ + test AnnotateQualityTaskId (get) + """ + + # Arrange + # Mock the Task.objects.get method to return mock tasks + mock_get.return_value = self.task1 + + request = self.factory.get('/dummy-url') + self._set_up_session(request) + request.user = self.user + + # Act + response = AnnotateQualityTaskId(request, self.task1.id) + + # Assert + self.assertEqual(response.status_code, 200) + self.assertEqual(self.task1.remarks['quality_taskid'], 'initial remark for task_id') + + @patch('taskdatabase.models.Task.objects.get') + @patch('taskdatabase.models.Task.objects.filter') + def test_clear_annotations_sas_id(self, mock_filter, mock_get): + # Arrange + # Mock the queryset returned by Task.objects.filter + mock_get.return_value = self.task1 + mock_filter.return_value = [self.task1, self.task2] + + request = MagicMock() + + # Act + response = ClearAnnotationsSasID(request, id=self.task1.id) + + # Asserts + self.assertEqual(response.status_code, 302) # Redirect status code + self.assertEqual(response.url, reverse('validation')) + + # Verify that the remarks were cleared + self.assertIsNone(self.task1.remarks['quality_sasid']) + self.assertIsNone(self.task2.remarks['quality_sasid']) diff --git a/atdb/taskdatabase/tests/test_views_details_page.py b/atdb/taskdatabase/tests/test_views_details_page.py index fec78527b081ac1c9e5fafca954f2fa2f967e84f..ef3145104b328fb787645bf372d1371f41a9042e 100644 --- a/atdb/taskdatabase/tests/test_views_details_page.py +++ b/atdb/taskdatabase/tests/test_views_details_page.py @@ -1,27 +1,93 @@ -from django.test import TestCase +from django.test import TestCase, RequestFactory from django.urls import reverse +from unittest.mock import patch, MagicMock from taskdatabase.models import Task, Workflow -class DetailsPageViewTest(TestCase): +from taskdatabase.views import ShowInspectionPlots, ShowInspectionPlotsSasId,ShowSummarySasId + +class TestDetailsPage(TestCase): @classmethod - def setUp(cls): + def setUp(self): + self.factory = RequestFactory() + # Set up non-modified objects used by all test methods workflow = Workflow() workflow.save() # create a list of Tasks - Task.objects.get_or_create(sas_id=12345, status='finished', workflow=workflow) + self.task1 = Task.objects.create(sas_id=12345, status='finished', workflow=workflow) def test_url_exists_at_desired_location(self): # extract the task - task = Task.objects.all()[0] - response = self.client.get(f'/atdb/task_details/{task.id}/1') + response = self.client.get(f'/atdb/task_details/{self.task1.id}/1') self.assertEqual(response.status_code, 200) def test_uses_correct_template(self): - task = Task.objects.all()[0] - response = self.client.get(f'/atdb/task_details/{task.id}/1') + response = self.client.get(f'/atdb/task_details/{self.task1.id}/1') + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'taskdatabase/tasks/task_details.html') + + def test_show_inputs(self): + response = self.client.get(f'/atdb/show-inputs/{self.task1.id}/') + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'taskdatabase/details/inputs.html') + + def test_show_outputs(self): + response = self.client.get(f'/atdb/show-outputs/{self.task1.id}/') + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'taskdatabase/details/outputs.html') + + def test_show_metrics(self): + response = self.client.get(f'/atdb/show-metrics/{self.task1.id}/') + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'taskdatabase/details/metrics.html') + + @patch('taskdatabase.views.algorithms.construct_inspectionplots') + def test_show_inspectionplots(self,mock_plots): + # Arrange + mock_plots.return_value = "<p>Inspection Plots HTML</p>" + # Simulate a GET request to the view + request = self.factory.get('/show_inspectionplots/') + + # Act + response = ShowInspectionPlots(request, id=self.task1.id) + + # Assert self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'taskdatabase/tasks/task_details.html') \ No newline at end of file + + # Assert that the my_plots context contains the mocked HTML + self.assertIn('Inspection Plots HTML', response.content.decode()) + + @patch('taskdatabase.views.algorithms.construct_inspectionplots') + def test_show_inspectionplots_sasid(self,mock_plots): + # Arrange + mock_plots.return_value = "<p>Inspection Plots HTML</p>" + # Simulate a GET request to the view + request = self.factory.get('/show_inspectionplots_sasid/') + + # Act + response = ShowInspectionPlotsSasId(request, id=self.task1.id) + + # Assert + self.assertEqual(response.status_code, 200) + + # Assert that the my_plots context contains the mocked HTML + self.assertIn('Inspection Plots HTML', response.content.decode()) + + @patch('taskdatabase.views.algorithms.construct_summary') + def test_show_summary_sasid(self,mock_summary): + # Arrange + mock_summary.return_value = "<p>Summary HTML</p>" + # Simulate a GET request to the view + request = self.factory.get('/show_summary/') + + # Act + response = ShowSummarySasId(request, id=self.task1.id) + + # Assert + self.assertEqual(response.status_code, 200) + + # Assert that the my_plots context contains the mocked HTML + self.assertIn('<p>Summary HTML</p>', response.content.decode()) \ No newline at end of file diff --git a/atdb/taskdatabase/views.py b/atdb/taskdatabase/views.py index e572fd97cf6f743a2e87ed6e400c1c732c32a0e8..4445d4a913b5593332dd10644ac364fc3bcec271 100644 --- a/atdb/taskdatabase/views.py +++ b/atdb/taskdatabase/views.py @@ -1851,7 +1851,7 @@ def UpdateSummaryFlag(request, task_id): # pragma: no cover -def CreateStatusGraph(request): +def CreateStatusGraph(request): # pragma: no cover query_per_hour = """ SELECT DATE_TRUNC('hour', timestamp) AS hour,