def test_metadata_when_type_changed_case2(self, mock_check_extension, \
        mock_get_storage_backend, mock_move_resource_to_final_location):

        resource_path = os.path.join(VAL_TESTDIR, 'test_matrix.tsv')
        mock_move_resource_to_final_location.return_value = resource_path

        mock_f = mock.MagicMock()
        mock_f.get_local_resource_path.return_value = resource_path
        mock_get_storage_backend.return_value = mock_f
        mock_check_extension.return_value = True
        
        r = Resource.objects.create(
            name = 'test_annotation_valid.tsv',
            owner = self.regular_user_1,
            is_active=True,
            path = resource_path,
            resource_type = '*'
        )
        validate_resource(r, '*')
        rm = ResourceMetadata.objects.get(resource=r)
        self.assertTrue(rm.observation_set is None)
        r.save()
        validate_resource(r, 'MTX')
        rm = ResourceMetadata.objects.get(resource=r)
        obs_set = rm.observation_set
        samples = [x['id'] for x in obs_set['elements']]
        expected = ['SW1_Control','SW2_Control','SW3_Control','SW4_Treated','SW5_Treated','SW6_Treated']
        self.assertCountEqual(samples, expected)
    def test_proper_exceptions_raised_case3(self, \
        mock_check_extension, \
        mock_get_storage_backend, \
        mock_handle_valid_resource, \
        mock_get_resource_type_instance):
        '''
        If unexpected errors (like connecting to cloud storage occur), check that we raise exceptions
        that provide helpful errors.

        Here, we test if the `get_resource_type` function raises an exception from an unknown
        resource type (a keyError). 
        '''
        mock_check_extension.return_value = True
        mock_get_resource_type_instance.side_effect = [KeyError('abc'),]

        all_resources = Resource.objects.all()
        unset_resources = []
        for r in all_resources:
            if not r.resource_type:
                unset_resources.append(r)
        
        if len(unset_resources) == 0:
            raise ImproperlyConfigured('Need at least one'
                ' Resource without a type to test properly.'
            )

        unset_resource = unset_resources[0]

        with self.assertRaisesRegex(Exception, 'ZZZ'):
            validate_resource(unset_resource, 'ZZZ')
        mock_handle_valid_resource.assert_not_called()
        mock_get_storage_backend.assert_not_called()
        mock_get_resource_type_instance.assert_called()
    def test_metadata_when_type_changed(self, mock_check_extension, \
        mock_get_storage_backend, mock_move_resource_to_final_location):
        '''
        Checks that the update of resource metadata is updated. Related to a bug where
        a file was initially set to a general type (and thus the metadata was effectively empty).
        After trying to validate it as an annotation type, it was raising json serializer errors.
        '''
        resource_path = os.path.join(VAL_TESTDIR, 'test_annotation_valid.tsv')
        mock_move_resource_to_final_location.return_value = resource_path
        mock_check_extension.return_value = True
        mock_f = mock.MagicMock()
        mock_f.get_local_resource_path.return_value = resource_path
        mock_get_storage_backend.return_value = mock_f

        r = Resource.objects.create(
            name = 'test_annotation_valid.tsv',
            owner = self.regular_user_1,
            is_active=True,
            path = resource_path,
            resource_type = '*'
        )
        validate_resource(r, '*')
        rm = ResourceMetadata.objects.get(resource=r)
        self.assertTrue(rm.observation_set is None)
        validate_resource(r, 'ANN')
        rm = ResourceMetadata.objects.get(resource=r)
        self.assertFalse(rm.observation_set is None)
    def test_proper_exceptions_raised_case1(self, \
        mock_check_extension, \
        mock_get_storage_backend, \
        mock_handle_valid_resource, \
        mock_get_resource_type_instance):
        '''
        If unexpected errors (like connecting to cloud storage occur), check that we raise exceptions
        that provide helpful errors.

        Here, we test if the `check_extension` function raises an exception
        '''
        mock_check_extension.side_effect = [Exception('something unexpected!')]

        all_resources = Resource.objects.all()
        unset_resources = []
        for r in all_resources:
            if not r.resource_type:
                unset_resources.append(r)
        
        if len(unset_resources) == 0:
            raise ImproperlyConfigured('Need at least one'
                ' Resource without a type to test properly.'
            )

        unset_resource = unset_resources[0]

        with self.assertRaisesRegex(Exception, 'file extension'):
            validate_resource(unset_resource, 'MTX')
        mock_handle_valid_resource.assert_not_called()
        mock_get_storage_backend.assert_not_called()
        mock_get_resource_type_instance.assert_not_called()
    def test_invalid_handler_called(self, mock_check_extension, \
            mock_get_storage_backend, \
            mock_handle_invalid_resource, mock_get_resource_type_instance):
        '''
        Here we test that a failure to validate the resource calls the proper
        handler function.
        '''
        all_resources = Resource.objects.all()
        unset_resources = []
        for r in all_resources:
            if not r.resource_type:
                unset_resources.append(r)
        
        if len(unset_resources) == 0:
            raise ImproperlyConfigured('Need at least one'
                ' Resource without a type to test properly.'
            )

        unset_resource = unset_resources[0]

        mock_resource_class_instance = mock.MagicMock()
        mock_resource_class_instance.validate_type.return_value = (False, 'some string')
        mock_get_resource_type_instance.return_value = mock_resource_class_instance
        
        mock_storage_backend = mock.MagicMock()
        mock_storage_backend.get_local_resource_path.return_value = 'foo'
        mock_get_storage_backend.return_value = mock_storage_backend
        mock_check_extension.return_value = True

        validate_resource(unset_resource, 'MTX')

        mock_handle_invalid_resource.assert_called()
def validate_resource(resource_pk, requested_resource_type):
    '''
    This function only performs validation of the resource.
    Note that it calls the `resource_utilities.validate_resource` 
    function which does NOT perform a save on the passed Resource
    instance
    '''
    resource = resource_utilities.get_resource_by_pk(resource_pk)

    try:
        resource_utilities.validate_resource(resource, requested_resource_type)
    except Exception as ex:
        logger.info(
            'Caught an exception raised by the validate_resource function.')
        alert_admins(str(ex))
        resource.status = str(ex)
    resource.is_active = True
    resource.save()
    def test_proper_exceptions_raised_case4(self, \
        mock_check_extension, \
        mock_get_storage_backend, \
        mock_handle_valid_resource, \
        mock_get_resource_type_instance):
        '''
        If unexpected errors (like connecting to cloud storage occur), check that we raise exceptions
        that provide helpful errors.

        Here, we test if the get_local_resource_path (a method of the storage backend) fails
        for some unexpected reason, such as failure to connect to cloud storage
        '''
        mock_check_extension.return_value = True

        # here we mock there being a problem with the storage backend (maybe bucket storage
        # service is temporarily offline?)
        mock_storage_backend = mock.MagicMock()
        mock_storage_backend.get_local_resource_path.side_effect = [Exception('something bad')]
        mock_get_storage_backend.return_value = mock_storage_backend

        mock_resource_class_instance = mock.MagicMock()
        mock_resource_class_instance.performs_validation.return_value = True
        mock_get_resource_type_instance.return_value = mock_resource_class_instance

        all_resources = Resource.objects.all()
        unset_resources = []
        for r in all_resources:
            if not r.resource_type:
                unset_resources.append(r)
        
        if len(unset_resources) == 0:
            raise ImproperlyConfigured('Need at least one'
                ' Resource without a type to test properly.'
            )

        unset_resource = unset_resources[0]

        expected_message_partial = ('An unexpected issue occurred when'
            ' moving the file for inspection')
        with self.assertRaisesRegex(Exception, expected_message_partial):
            validate_resource(unset_resource, 'MTX')
    
        mock_resource_class_instance.validate_type.assert_not_called()
        mock_handle_valid_resource.assert_not_called()
    def test_proper_steps_taken_with_wildcard_resource(self, mock_check_extension, \
        mock_get_storage_backend, \
        mock_handle_valid_resource, \
        mock_get_resource_type_instance):
        '''
        Here we test that a esource type with a "wildcard" type goes through the proper
        steps. That is, we should skip the validation, etc.
        '''
        all_resources = Resource.objects.all()
        r = all_resources[0]

        mock_check_extension.return_value = True
        g = GeneralResource()
        mock_get_resource_type_instance.return_value = g

        validate_resource(r, WILDCARD)

        mock_handle_valid_resource.assert_called()
        mock_get_storage_backend.assert_not_called()
    def test_proper_exceptions_raised_case5(self, \
        mock_check_extension, \
        mock_get_storage_backend, \
        mock_handle_valid_resource, \
        mock_get_resource_type_instance):
        '''
        If unexpected errors (like connecting to cloud storage occur), check that we raise exceptions
        that provide helpful errors.

        Here, we test if the validation method fails unexpectedly.
        '''
        mock_check_extension.return_value = True
        mock_local_path = '/some/local/path.txt'
        mock_storage_backend = mock.MagicMock()
        mock_storage_backend.get_local_resource_path.return_value = mock_local_path
        mock_get_storage_backend.return_value = mock_storage_backend
        mock_resource_class_instance = mock.MagicMock()
        mock_resource_class_instance.performs_validation.return_value = True
        mock_resource_class_instance.validate_type.side_effect = [Exception('something unexpected.')]
        mock_get_resource_type_instance.return_value = mock_resource_class_instance

        all_resources = Resource.objects.all()
        unset_resources = []
        for r in all_resources:
            if not r.resource_type:
                unset_resources.append(r)
        
        if len(unset_resources) == 0:
            raise ImproperlyConfigured('Need at least one'
                ' Resource without a type to test properly.'
            )

        unset_resource = unset_resources[0]

        with self.assertRaisesRegex(Exception, Resource.UNEXPECTED_VALIDATION_ERROR):
            validate_resource(unset_resource, 'MTX')

        mock_handle_valid_resource.assert_not_called()
    def test_proper_valid_handler_called(self, \
        mock_check_extension, \
        mock_get_storage_backend, \
        mock_handle_valid_resource, \
        mock_get_resource_type_instance):
        '''
        Here we test that a successful validation calls the proper
        handler function.
        '''
        mock_local_path = '/some/local/path.txt'
        mock_storage_backend = mock.MagicMock()
        mock_storage_backend.get_local_resource_path.return_value = mock_local_path
        mock_get_storage_backend.return_value = mock_storage_backend

        mock_resource_class_instance = mock.MagicMock()
        mock_resource_class_instance.performs_validation.return_value = True
        mock_resource_class_instance.validate_type.return_value = (True, 'some string')
        mock_get_resource_type_instance.return_value = mock_resource_class_instance

        mock_check_extension.return_value = True

        all_resources = Resource.objects.all()
        unset_resources = []
        for r in all_resources:
            if not r.resource_type:
                unset_resources.append(r)
        
        if len(unset_resources) == 0:
            raise ImproperlyConfigured('Need at least one'
                ' Resource without a type to test properly.'
            )

        unset_resource = unset_resources[0]


        validate_resource(unset_resource, 'MTX')

        mock_handle_valid_resource.assert_called()