"""Test data_manager.managers module functionality. This file tests the core functionality of the excluded_fields_for_evaluation feature that optimizes task API performance by excluding expensive fields. """ from unittest.mock import Mock, patch from django.test import TestCase class TestExcludedFieldsLogic(TestCase): """Test the core logic of excluded_fields_for_evaluation functionality. This test validates step by step: - The field inclusion/exclusion logic works correctly - Edge cases are handled properly - The boolean logic matches expected behavior Critical validation: The core logic that determines whether a field should be included based on fields_for_evaluation, all_fields, and excluded_fields_for_evaluation parameters works correctly. """ def test_field_inclusion_logic(self): """Test the core field inclusion logic used in annotate_queryset. This test validates step by step: - Testing various combinations of parameters - Verifying the boolean logic is correct - Ensuring all edge cases are covered Critical validation: The logic (field in fields_for_evaluation or all_fields) and field not in excluded_fields_for_evaluation works as expected. """ # Test scenarios: (fields_for_evaluation, all_fields, excluded_fields, field, expected_result) test_scenarios = [ # Scenario 1: all_fields=True, field not excluded (['field1'], True, [], 'field2', True), # Scenario 2: all_fields=True, field excluded (['field1'], True, ['field2'], 'field2', False), # Scenario 3: field in fields_for_evaluation, not excluded (['field1'], False, [], 'field1', True), # Scenario 4: field in fields_for_evaluation, but excluded (['field1'], False, ['field1'], 'field1', False), # Scenario 5: field not in fields_for_evaluation, all_fields=False (['field1'], False, [], 'field2', False), # Scenario 6: empty exclusion list behaves like None (['field1'], True, [], 'field2', True), # Scenario 7: None exclusion list (['field1'], True, None, 'field2', True), # Scenario 8: Multiple exclusions (['field1', 'field2', 'field3'], True, ['field2', 'field3'], 'field1', True), (['field1', 'field2', 'field3'], True, ['field2', 'field3'], 'field2', False), ] for fields_for_eval, all_fields, excluded_fields, test_field, expected in test_scenarios: with self.subTest( fields_for_eval=fields_for_eval, all_fields=all_fields, excluded_fields=excluded_fields, test_field=test_field, ): # Apply the same logic used in annotate_queryset if excluded_fields is None: excluded_fields = [] should_include = (test_field in fields_for_eval or all_fields) and test_field not in excluded_fields self.assertEqual( should_include, expected, f"Field inclusion logic failed for field '{test_field}' with " f'fields_for_eval={fields_for_eval}, all_fields={all_fields}, ' f'excluded_fields={excluded_fields}', ) def test_excluded_fields_none_handling(self): """Test that None excluded_fields_for_evaluation is handled correctly. This test validates step by step: - Passing None as excluded_fields_for_evaluation - Verifying it's treated as an empty list - Ensuring no fields are excluded when None is passed Critical validation: None values for excluded_fields_for_evaluation should not cause errors and should behave as if no exclusions were specified. """ # Test the logic with None exclusions fields_for_evaluation = ['field1', 'field2'] excluded_fields = None # This simulates the None check in annotate_queryset if excluded_fields is None: excluded_fields = [] # Test that fields are included when not in exclusion list for field in fields_for_evaluation: should_include = (field in fields_for_evaluation or False) and field not in excluded_fields self.assertTrue(should_include, f"Field '{field}' should be included when excluded_fields is None") def test_performance_optimization_fields(self): """Test specific performance optimization field combinations. This test validates step by step: - Testing the exact field combinations used in the performance optimization - Verifying expensive fields are excluded when specified - Ensuring normal fields are still included Critical validation: The specific optimization used in the TaskAPI (excluding annotations_results and predictions_results) works correctly. """ # These are the actual fields used in the performance optimization expensive_fields = ['annotations_results', 'predictions_results'] normal_fields = ['completed_at', 'avg_lead_time', 'draft_exists', 'annotators'] all_fields = expensive_fields + normal_fields # Test with all_fields=True and expensive field exclusions excluded_fields = expensive_fields for field in all_fields: with self.subTest(field=field): should_include = ( field in [] or True ) and field not in excluded_fields # all_fields=True, no specific fields_for_evaluation if field in expensive_fields: self.assertFalse(should_include, f"Expensive field '{field}' should be excluded") else: self.assertTrue(should_include, f"Normal field '{field}' should be included") class TestPreparedTaskManagerBehavior(TestCase): """Test PreparedTaskManager behavior with mock annotation functions. This test validates step by step: - The annotate_queryset method calls the right functions - Excluded fields are properly skipped - The overall flow works correctly Critical validation: The excluded_fields_for_evaluation feature properly controls which annotation functions are executed. """ def test_annotate_queryset_with_simple_functions(self): """Test annotate_queryset with simple trackable annotation functions. This test validates step by step: - Creating simple annotation functions that can be tracked - Calling annotate_queryset with exclusions - Verifying which functions were called vs skipped Critical validation: The exclusion logic properly controls function execution. """ from data_manager.managers import PreparedTaskManager # Create a simple mock queryset mock_queryset = Mock() mock_queryset.first.return_value = None # No first task # Create trackable annotation functions called_functions = [] def make_annotation_function(field_name): def annotation_function(queryset): called_functions.append(field_name) return queryset return annotation_function # Create test annotation map test_annotations = { 'annotations_results': make_annotation_function('annotations_results'), 'predictions_results': make_annotation_function('predictions_results'), 'completed_at': make_annotation_function('completed_at'), 'avg_lead_time': make_annotation_function('avg_lead_time'), } with patch('data_manager.managers.get_annotations_map', return_value=test_annotations): manager = PreparedTaskManager() # Test with excluded fields called_functions.clear() manager.annotate_queryset( queryset=mock_queryset, all_fields=True, excluded_fields_for_evaluation=['annotations_results', 'predictions_results'], ) # Validation: Only non-excluded fields should have been called self.assertIn('completed_at', called_functions, "Non-excluded field 'completed_at' should be processed") self.assertIn('avg_lead_time', called_functions, "Non-excluded field 'avg_lead_time' should be processed") self.assertNotIn( 'annotations_results', called_functions, "Excluded field 'annotations_results' should not be processed" ) self.assertNotIn( 'predictions_results', called_functions, "Excluded field 'predictions_results' should not be processed" ) def test_annotate_queryset_without_exclusions(self): """Test annotate_queryset without any exclusions. This test validates step by step: - Creating annotation functions with no exclusions - Verifying all functions are called - Ensuring backward compatibility Critical validation: When no exclusions are specified, all fields should be processed maintaining existing behavior. """ from data_manager.managers import PreparedTaskManager mock_queryset = Mock() mock_queryset.first.return_value = None called_functions = [] def make_annotation_function(field_name): def annotation_function(queryset): called_functions.append(field_name) return queryset return annotation_function test_annotations = { 'annotations_results': make_annotation_function('annotations_results'), 'predictions_results': make_annotation_function('predictions_results'), 'completed_at': make_annotation_function('completed_at'), } with patch('data_manager.managers.get_annotations_map', return_value=test_annotations): manager = PreparedTaskManager() # Test without excluded fields called_functions.clear() manager.annotate_queryset(queryset=mock_queryset, all_fields=True, excluded_fields_for_evaluation=None) # Validation: All fields should have been called self.assertIn( 'annotations_results', called_functions, "Field 'annotations_results' should be processed when not excluded", ) self.assertIn( 'predictions_results', called_functions, "Field 'predictions_results' should be processed when not excluded", ) self.assertIn( 'completed_at', called_functions, "Field 'completed_at' should be processed when not excluded" ) def test_annotate_queryset_with_specific_fields(self): """Test annotate_queryset with specific fields_for_evaluation and exclusions. This test validates step by step: - Specifying particular fields for evaluation - Adding exclusions to those fields - Verifying only the right subset is processed Critical validation: The combination of fields_for_evaluation and excluded_fields_for_evaluation works correctly together. """ from data_manager.managers import PreparedTaskManager mock_queryset = Mock() mock_queryset.first.return_value = None called_functions = [] def make_annotation_function(field_name): def annotation_function(queryset): called_functions.append(field_name) return queryset return annotation_function test_annotations = { 'annotations_results': make_annotation_function('annotations_results'), 'predictions_results': make_annotation_function('predictions_results'), 'completed_at': make_annotation_function('completed_at'), 'avg_lead_time': make_annotation_function('avg_lead_time'), } with patch('data_manager.managers.get_annotations_map', return_value=test_annotations): manager = PreparedTaskManager() # Test with specific fields and exclusions called_functions.clear() manager.annotate_queryset( queryset=mock_queryset, fields_for_evaluation=['annotations_results', 'completed_at', 'avg_lead_time'], excluded_fields_for_evaluation=['annotations_results'], ) # Validation: Only non-excluded fields from fields_for_evaluation should be called self.assertNotIn( 'annotations_results', called_functions, "Excluded field 'annotations_results' should not be processed" ) self.assertIn('completed_at', called_functions, "Non-excluded field 'completed_at' should be processed") self.assertIn('avg_lead_time', called_functions, "Non-excluded field 'avg_lead_time' should be processed") self.assertNotIn( 'predictions_results', called_functions, "Field 'predictions_results' should not be processed (not in fields_for_evaluation)", ) class TestGetQuerysetParameterPassing(TestCase): """Test that get_queryset properly passes excluded_fields_for_evaluation parameter. This test validates step by step: - The get_queryset method accepts the parameter - The parameter is passed through to annotate_queryset - Default values work correctly Critical validation: The get_queryset method serves as the main interface and properly forwards the optimization parameters. """ def test_get_queryset_parameter_interface(self): """Test that get_queryset accepts excluded_fields_for_evaluation parameter. This test validates step by step: - Calling get_queryset with the excluded_fields_for_evaluation parameter - Ensuring the method accepts the parameter without errors - Verifying the interface is correctly defined Critical validation: The public API properly accepts the optimization parameter. """ from data_manager.managers import PreparedTaskManager from data_manager.models import PrepareParams manager = PreparedTaskManager() mock_prepare_params = Mock(spec=PrepareParams) mock_prepare_params.project = 1 mock_prepare_params.request = Mock() # This should not raise any errors with patch.object(manager, 'only_filtered') as mock_only_filtered, patch.object( manager, 'annotate_queryset' ) as mock_annotate: mock_queryset = Mock() mock_only_filtered.return_value = mock_queryset mock_annotate.return_value = mock_queryset # Test with excluded_fields_for_evaluation parameter manager.get_queryset( prepare_params=mock_prepare_params, all_fields=True, excluded_fields_for_evaluation=['annotations_results', 'predictions_results'], ) # Validation: annotate_queryset should be called with the parameter mock_annotate.assert_called_once() call_kwargs = mock_annotate.call_args[1] self.assertEqual( call_kwargs.get('excluded_fields_for_evaluation'), ['annotations_results', 'predictions_results'], 'excluded_fields_for_evaluation should be passed to annotate_queryset', ) def test_get_queryset_default_parameter_handling(self): """Test that get_queryset handles default parameter values correctly. This test validates step by step: - Calling get_queryset without excluded_fields_for_evaluation - Verifying the parameter defaults appropriately - Ensuring backward compatibility Critical validation: When the parameter is not provided, the behavior should remain unchanged from the original implementation. """ from data_manager.managers import PreparedTaskManager from data_manager.models import PrepareParams manager = PreparedTaskManager() mock_prepare_params = Mock(spec=PrepareParams) mock_prepare_params.project = 1 mock_prepare_params.request = Mock() with patch.object(manager, 'only_filtered') as mock_only_filtered, patch.object( manager, 'annotate_queryset' ) as mock_annotate: mock_queryset = Mock() mock_only_filtered.return_value = mock_queryset mock_annotate.return_value = mock_queryset # Test without excluded_fields_for_evaluation parameter manager.get_queryset(prepare_params=mock_prepare_params, all_fields=True) # Validation: annotate_queryset should be called with None for excluded fields mock_annotate.assert_called_once() call_kwargs = mock_annotate.call_args[1] self.assertIsNone( call_kwargs.get('excluded_fields_for_evaluation'), 'excluded_fields_for_evaluation should default to None', )