def test_resource_type_does_not_change_if_validation_fails(self, \ mock_add_metadata_to_resource ): ''' If we had previously validated a resource successfully, requesting a change that fails validation results in NO change to the resource_type attribute ''' all_resources = Resource.objects.all() set_resources = [] for r in all_resources: if r.resource_type: set_resources.append(r) if len(set_resources) == 0: raise ImproperlyConfigured('Need at least one' ' Resource with a type to test properly.' ) resource = set_resources[0] original_type = resource.resource_type other_type = original_type while other_type == original_type: other_type = random.choice(list(RESOURCE_MAPPING.keys())) handle_invalid_resource(resource, other_type) self.assertTrue(resource.resource_type == original_type) self.assertTrue(resource.status.startswith(Resource.REVERTED.format( requested_resource_type=DB_RESOURCE_STRING_TO_HUMAN_READABLE[other_type], original_resource_type = DB_RESOURCE_STRING_TO_HUMAN_READABLE[original_type]) )) mock_add_metadata_to_resource.assert_not_called()
def test_operationdataresource_input_spec(self): from resource_types import RESOURCE_MAPPING all_resource_types = list(RESOURCE_MAPPING.keys()) random.shuffle(all_resource_types) n = 2 valid_resource_types = [all_resource_types[i] for i in range(n)] ds = OperationDataResourceInputSpec( many=True, resource_type=valid_resource_types[0]) ds = OperationDataResourceInputSpec( many=1, resource_type=valid_resource_types[0]) ds = OperationDataResourceInputSpec( many='true', resource_type=valid_resource_types[0]) # missing `resource_types` key with self.assertRaises(ValidationError): ds = OperationDataResourceInputSpec(many=True) # missing `many` key with self.assertRaises(ValidationError): ds = OperationDataResourceInputSpec( resource_type=valid_resource_types[0]) # `many` key cannot be cast as a boolean with self.assertRaises(ValidationError): ds = OperationDataResourceInputSpec( many='yes', resource_type=valid_resource_types[0]) # `resource_type` key has bad value with self.assertRaises(ValidationError): ds = OperationDataResourceInputSpec(many=True, resource_type='abc') # `resource_types` key is a list with self.assertRaises(ValidationError): ds = OperationDataResourceInputSpec( many=True, resource_type=valid_resource_types)
def test_all_resources_have_acceptable_extensions(self): ''' If any of the resource types are missing the ACCEPTABLE_EXTENSIONS key, then this test will raise an AttributeError ''' for k,v in RESOURCE_MAPPING.items(): v.ACCEPTABLE_EXTENSIONS
def setUp(self): self.min_val = 0 self.max_val = 4 self.output_spec_dict1 = { 'attribute_type': 'BoundedInteger', 'min': self.min_val, 'max': self.max_val, } self.output_spec1 = BoundedIntegerOutputSpec( min=self.min_val, max=self.max_val ) self.expected_spec_result1 = { 'attribute_type': 'BoundedInteger', 'min': self.min_val, 'max': self.max_val } self.valid_operation_output1={ 'required': True, 'spec': self.output_spec_dict1 } self.expected_result1 = self.valid_operation_output1.copy() self.expected_result1['spec'] = self.expected_spec_result1 all_resource_types = list(RESOURCE_MAPPING.keys()) random.shuffle(all_resource_types) self.rt = all_resource_types[0] self.output_spec_dict2 = { 'attribute_type': 'DataResource', 'resource_type': self.rt, 'many': False } self.output_spec2 = DataResourceOutputSpec( many=False, resource_type=self.rt ) self.expected_spec_result2 = { 'attribute_type': 'DataResource', 'many': False, 'resource_type': self.rt } self.valid_operation_output2={ 'required': True, 'spec': self.output_spec_dict2 } # this is invalid since it's missing the 'required' key self.invalid_operation_output={ 'spec': self.output_spec_dict2 } self.expected_result2 = self.valid_operation_output2.copy() self.expected_result2['spec'] = self.expected_spec_result2 self.optional_operation_output = { 'required': False, 'spec': self.output_spec_dict2 }
def test_resource_type_change_succeeds(self, mock_get_storage_backend, mock_get_resource_type_instance, mock_move, mock_check_extension): ''' Here we test that a Resource change request succeeds on a Resource that had an existing type. ''' all_resources = Resource.objects.all() set_resources = [] for r in all_resources: if r.resource_type: set_resources.append(r) if len(set_resources) == 0: raise ImproperlyConfigured( 'Need at least one' ' Resource with a defined type to test properly.') # just grab the first resource to use for the test resource = set_resources[0] # Need to know # what it was in the first place. We then randomly # choose a different type original_type = resource.resource_type new_type = original_type while new_type == original_type: new_type = random.choice(list(RESOURCE_MAPPING.keys())) # set the mock return values new_path = '/some/mock/path.tsv' mock_move.return_value = new_path mock_resource_instance = mock.MagicMock() mock_resource_instance.validate_type.return_value = (True, 'some string') mock_resource_instance.extract_metadata.return_value = { PARENT_OP_KEY: None, OBSERVATION_SET_KEY: None, FEATURE_SET_KEY: None } mock_resource_instance.save_in_standardized_format.return_value = ( '/some/path.txt', 'newname') mock_get_resource_type_instance.return_value = mock_resource_instance mock_check_extension.return_value = True mock_storage_backend = mock.MagicMock() mock_storage_backend.get_local_resource_path.return_value = new_path mock_get_storage_backend.return_value = mock_storage_backend validate_resource(resource.pk, new_type) # query the resource to see any changes: current_resource = Resource.objects.get(pk=resource.pk) self.assertTrue(current_resource.is_active) self.assertEqual(current_resource.resource_type, new_type) self.assertFalse(current_resource.resource_type == original_type) self.assertEqual(current_resource.status, Resource.READY) self.assertEqual(current_resource.path, new_path) mock_move.assert_called()
def validate_keyword_args(self, kwargs_dict): try: self.resource_types = kwargs_dict.pop(self.RESOURCE_TYPES_KEY) except KeyError as ex: raise ValidationError( 'The "{key}" key is required.'.format(key=ex)) if not type(self.resource_types) == list: raise ValidationError('The {key} key needs to be a list.'.format( key=self.RESOURCE_TYPES_KEY)) from resource_types import RESOURCE_MAPPING for r in self.resource_types: if not r in RESOURCE_MAPPING.keys(): raise ValidationError( 'The resource type {rt} is not valid.' ' Needs to be one of the following: {csv}.'.format( rt=r, csv=', '.join(RESOURCE_MAPPING.keys()))) return kwargs_dict
def test_variable_dataresource_output_spec(self): from resource_types import RESOURCE_MAPPING all_resource_types = list(RESOURCE_MAPPING.keys()) random.shuffle(all_resource_types) n = 2 valid_resource_types = [all_resource_types[i] for i in range(n)] ds = VariableDataResourceOutputSpec( many=True, resource_types=valid_resource_types) ds = VariableDataResourceOutputSpec( many=1, resource_types=valid_resource_types) ds = VariableDataResourceOutputSpec( many='true', resource_types=valid_resource_types) # missing `resource_types` key with self.assertRaises(ValidationError): ds = VariableDataResourceOutputSpec(many=True) # missing `many` key with self.assertRaises(ValidationError): ds = VariableDataResourceOutputSpec( resource_types=valid_resource_types) # uses `resource_type` key, which is effectively the same # as the `resource_types` key being missing. However, this tests # the error more explicitly since it is likely to be common with self.assertRaises(ValidationError): ds = VariableDataResourceOutputSpec( many='yes', resource_type=valid_resource_types) # `many` key cannot be cast as a boolean with self.assertRaises(ValidationError): ds = VariableDataResourceOutputSpec( many='yes', resource_types=valid_resource_types) # `resource_types` key has bad value with self.assertRaises(ValidationError): ds = VariableDataResourceOutputSpec(many=True, resource_types=['abc', 'MTX']) # `resource_types` key is NOT a list with self.assertRaises(ValidationError): ds = VariableDataResourceOutputSpec(many=True, resource_types='MTX') # `resource_types` key is a wildcard (e.g. for remote uploads where we don't # know ahead of time what the file type is) ds = VariableDataResourceOutputSpec(many=True, resource_types=[ '*', ])
def test_invalid_type_remains_invalid_case2( self, mock_get_storage_backend, mock_get_resource_type_instance, mock_check_extension): ''' Here we test that a Resource change request fails. The Resource previously had a valid type (or it would not have been set) and we check that a failed request "reverts" to the most recent valid resource type ''' all_resources = Resource.objects.all() set_resources = [] for r in all_resources: if r.resource_type: set_resources.append(r) if len(set_resources) == 0: raise ImproperlyConfigured( 'Need at least one' ' Resource with a defined type to test properly.') # just grab the first resource to use for the test resource = set_resources[0] # need to test the reversion of type, so need to know # what it was in the first place. We then randomly # choose a different type current_type = resource.resource_type other_type = current_type while other_type == current_type: other_type = random.choice(list(RESOURCE_MAPPING.keys())) mock_resource_instance = mock.MagicMock() failure_msg = 'Failed for this reason.' mock_resource_instance.validate_type.return_value = (False, failure_msg) mock_get_resource_type_instance.return_value = mock_resource_instance mock_check_extension.return_value = True validate_resource(resource.pk, other_type) # query the resource to see any changes: current_resource = Resource.objects.get(pk=resource.pk) self.assertTrue(current_resource.is_active) self.assertEqual(current_resource.resource_type, current_type) expected_status = Resource.REVERTED.format( requested_resource_type=DB_RESOURCE_STRING_TO_HUMAN_READABLE[ other_type], original_resource_type=DB_RESOURCE_STRING_TO_HUMAN_READABLE[ current_type]) expected_status = expected_status + ' ' + failure_msg self.assertEqual(current_resource.status, expected_status)
def test_variable_dataresource_input_spec(self): from resource_types import RESOURCE_MAPPING all_resource_types = list(RESOURCE_MAPPING.keys()) random.shuffle(all_resource_types) n = 2 valid_resource_types = [all_resource_types[i] for i in range(n)] ds = VariableDataResourceInputSpec(many=True, resource_types=valid_resource_types) ds = VariableDataResourceInputSpec(many=1, resource_types=valid_resource_types) ds = VariableDataResourceInputSpec(many='true', resource_types=valid_resource_types) # missing `resource_types` key with self.assertRaises(ValidationError): ds = VariableDataResourceInputSpec(many=True) # missing `many` key with self.assertRaises(ValidationError): ds = VariableDataResourceInputSpec( resource_types=valid_resource_types) # uses `resource_type` key, which is effectively the same # as the `resource_types` key being missing. However, this tests # the error more explicitly since it is likely to be common with self.assertRaises(ValidationError): ds = DataResourceInputSpec(resource_type=valid_resource_types, many=True) # `many` key cannot be cast as a boolean with self.assertRaises(ValidationError): ds = VariableDataResourceInputSpec( many='yes', resource_types=valid_resource_types) # `resource_types` key has bad values with self.assertRaises(ValidationError): ds = VariableDataResourceInputSpec(many=True, resource_types=[ 'abc', ]) # `resource_types` key is not a list. Here, just a string. with self.assertRaises(ValidationError): ds = VariableDataResourceInputSpec( many=True, resource_types=valid_resource_types[0])
def test_dataresource_input_spec(self): from resource_types import RESOURCE_MAPPING all_resource_types = list(RESOURCE_MAPPING.keys()) random.shuffle(all_resource_types) valid_resource_type = all_resource_types[0] ds = DataResourceInputSpec(many=True, resource_type=valid_resource_type) ds = DataResourceInputSpec(many=1, resource_type=valid_resource_type) ds = DataResourceInputSpec(many='true', resource_type=valid_resource_type) # missing `resource_type` key with self.assertRaises(ValidationError): ds = DataResourceInputSpec(many=True) # uses `resource_typeS` key, which is effectively the same # as the `resource_type` key being missing. However, this tests # the error more explicitly since it is likely to be common with self.assertRaises(ValidationError): ds = DataResourceInputSpec(resource_types=valid_resource_type, many=True) # missing `many` key with self.assertRaises(ValidationError): ds = DataResourceInputSpec(resource_type=valid_resource_type) # `many` key cannot be cast as a boolean with self.assertRaises(ValidationError): ds = DataResourceInputSpec(many='yes', resource_type=valid_resource_type) # `resource_type` key has an invalid type with self.assertRaises(ValidationError): ds = DataResourceInputSpec(many=True, resource_type='abc') # `resource_type` key is not a string. Here, it's a list with self.assertRaises(ValidationError): ds = DataResourceInputSpec(many=True, resource_type=[ valid_resource_type, ])
def setUp(self): all_resource_types = list(RESOURCE_MAPPING.keys()) random.shuffle(all_resource_types) self.op_output1_dict = { 'required': True, 'spec': { 'attribute_type': 'DataResource', 'resource_type': all_resource_types[0], 'many': False } } self.op_output2_dict = { 'required': True, 'spec': { 'attribute_type': 'BoundedInteger', 'max': 10, 'min': 0 } } # this is missing the `required` key self.invalid_op_output_dict = { 'spec': { 'attribute_type': 'BoundedInteger', 'max': 10, 'min': 0 } } self.op_output1 = OperationOutputSerializer( data=self.op_output1_dict).get_instance() self.op_output2 = OperationOutputSerializer( data=self.op_output2_dict).get_instance() self.operation_output_dict = { 'abc': self.op_output1_dict, 'xyz': self.op_output2_dict } self.invalid_op_output = {'abc': self.invalid_op_output_dict}
def test_dataresource_output_spec(self): from resource_types import RESOURCE_MAPPING all_resource_type = list(RESOURCE_MAPPING.keys()) random.shuffle(all_resource_type) valid_resource_type = all_resource_type[0] ds = DataResourceOutputSpec(many=True, resource_type=valid_resource_type) ds = DataResourceOutputSpec(many=1, resource_type=valid_resource_type) ds = DataResourceOutputSpec(many='true', resource_type=valid_resource_type) # missing `resource_type` key with self.assertRaises(ValidationError): ds = DataResourceOutputSpec(many=True) # missing `many` key with self.assertRaises(ValidationError): ds = DataResourceOutputSpec(resource_type=valid_resource_type) # `many` key cannot be cast as a boolean with self.assertRaises(ValidationError): ds = DataResourceOutputSpec(many='yes', resource_type=valid_resource_type) # `resource_type` key has bad value with self.assertRaises(ValidationError): ds = DataResourceOutputSpec(many=True, resource_type='abc') # `resource_type` key is a list with self.assertRaises(ValidationError): ds = DataResourceOutputSpec(many=True, resource_type=[ valid_resource_type, ]) # `resource_type` key is a wildcard (e.g. for remote uploads where we don't # know ahead of time what the file type is) ds = DataResourceOutputSpec(many=True, resource_type='*')
def setUp(self): all_resource_types = list(RESOURCE_MAPPING.keys()) random.shuffle(all_resource_types) # an OperationInput self.op_input1_dict = { 'description': 'The count matrix of expressions', 'name': 'Count matrix:', 'required': True, 'spec': { 'attribute_type': 'DataResource', 'resource_type': all_resource_types[0], 'many': False } } # another OperationInput self.op_input2_dict = { 'description': 'The filtering threshold for the p-value', 'name': 'P-value threshold:', 'required': False, 'spec': { 'attribute_type': 'BoundedFloat', 'min': 0, 'max': 1.0, 'default': 0.05 } } self.op_input1 = OperationInputSerializer( data=self.op_input1_dict).get_instance() self.op_input2 = OperationInputSerializer( data=self.op_input2_dict).get_instance() self.operation_input_dict = { 'count_matrix': self.op_input1_dict, 'p_val': self.op_input2_dict }
def setUp(self): all_resource_types = list(RESOURCE_MAPPING.keys()) random.shuffle(all_resource_types) # an OperationInput self.op_input1_dict = { 'description': 'The count matrix of expressions', 'name': 'Count matrix:', 'required': True, 'spec': { 'attribute_type': 'DataResource', 'resource_type': all_resource_types[0], 'many': False } } # another OperationInput self.op_input2_dict = { 'description': 'The filtering threshold for the p-value', 'name': 'P-value threshold:', 'required': False, 'spec': { 'attribute_type': 'BoundedFloat', 'min': 0, 'max': 1.0, 'default': 0.05 } } self.op_output1_dict = { 'required': True, 'spec': { 'attribute_type': 'DataResource', 'resource_type': all_resource_types[0], 'many': False } } self.op_output2_dict = { 'required': True, 'spec': { 'attribute_type': 'DataResource', 'resource_type': all_resource_types[1], 'many': True } } op_input1 = OperationInputSerializer( data=self.op_input1_dict).get_instance() op_input2 = OperationInputSerializer( data=self.op_input2_dict).get_instance() op_output1 = OperationOutputSerializer( data=self.op_output1_dict).get_instance() op_output2 = OperationOutputSerializer( data=self.op_output2_dict).get_instance() self.op_id = str(uuid.uuid4()) self.op_name = 'Some name' self.description = 'Here is some desc.' self.mode = AVAILABLE_RUN_MODES[0] self.repository_url = 'https://github.com/some-repo/' self.git_hash = 'abcd1234' self.repo_name = 'some-repo' self.workspace_operation = True inputs_dict = { 'count_matrix': self.op_input1_dict, 'p_val': self.op_input2_dict } outputs_dict = { 'norm_counts': self.op_output1_dict, 'dge_table': self.op_output2_dict } self.operation_dict = { 'id': self.op_id, 'name': self.op_name, 'description': self.description, 'inputs': inputs_dict, 'outputs': outputs_dict, 'mode': self.mode, 'repository_url': self.repository_url, 'git_hash': self.git_hash, 'repo_name': self.repo_name, 'workspace_operation': self.workspace_operation } op_input_dict = OperationInputDictSerializer( data=inputs_dict).get_instance() op_output_dict = OperationOutputDictSerializer( data=outputs_dict).get_instance() self.operation_instance = Operation(self.op_id, self.op_name, self.description, op_input_dict, op_output_dict, self.mode, self.repository_url, self.git_hash, self.repo_name, self.workspace_operation)
def test_variable_resource_type_input(self): ''' Tests the various scenarios for handling an input corresponding to a VariableDataResource ''' submitted_input_or_output_class = submitted_operation_input_or_output_mapping[ 'VariableDataResource'] user_workspaces = Workspace.objects.filter(owner=self.regular_user_1) has_valid_setup = False user_workspace = None for w in user_workspaces: workspace_resources = w.resources.all() user_resource_list = [] for r in workspace_resources: if (r.is_active) and (r.owner == self.regular_user_1): user_resource_list.append(r) if len(user_resource_list) >= 2: user_workspace = w has_valid_setup = True break if not has_valid_setup: raise ImproperlyConfigured( 'Need at least two active user' ' Resources in a single Workspace for this test.') # want to get another Resource owned by this user that is NOT in the workspace # They should NOT be able to execute an analysis on it unless it's associated with # the workspace. non_workspace_resources = [ x for x in Resource.objects.filter(owner=self.regular_user_1) if not x in user_resource_list ] if len(non_workspace_resources) == 0: raise ImproperlyConfigured( 'Need at least one Resource for the user that is not' ' associated with a workspace.') other_user_resource = Resource.objects.create( is_active=True, owner=self.regular_user_2) # handle a good case with a single file r = user_resource_list[0] rt = r.resource_type single_resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': False, 'resource_types': [ rt, ] } x = submitted_input_or_output_class(self.regular_user_1, None, user_workspace, 'xyz', str(r.id), single_resource_input_spec) self.assertEqual(x.get_value(), str(r.id)) # handle a good case with multiple files user_resource_dict = defaultdict(list) for r in user_resource_list: user_resource_dict[r.resource_type].append(r) rt = None for k, v in user_resource_dict.items(): if len(v) > 1: rt = k if rt: r0 = user_resource_dict[rt][0] r1 = user_resource_dict[rt][1] else: raise ImproperlyConfigured( 'Set up the test such that there are ' 'multiple resources with the same type.') multiple_resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': True, 'resource_types': [ rt, ] } expected_vals = [str(r0.id), str(r1.id)] x = submitted_input_or_output_class(self.regular_user_1, None, user_workspace, 'xyz', expected_vals, multiple_resource_input_spec) self.assertCountEqual(x.get_value(), expected_vals) # malformatted input_spec (uses resource_type...singular) r = user_resource_list[0] rt = r.resource_type single_resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': False, 'resource_type': [ rt, ] } with self.assertRaises(ValidationError): submitted_input_or_output_class(self.regular_user_1, None, user_workspace, 'xyz', str(r.id), single_resource_input_spec) # malformatted input_spec (resource_type should be a list, not a str) r = user_resource_list[0] rt = r.resource_type single_resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': False, 'resource_types': rt } with self.assertRaises(ValidationError): submitted_input_or_output_class(self.regular_user_1, None, user_workspace, 'xyz', str(r.id), single_resource_input_spec) # handle a single file with an invalid UUID; uuid is fine, but no Resource r = user_resource_list[0] rt = r.resource_type single_resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': False, 'resource_types': [ rt, ] } with self.assertRaises(ValidationError): submitted_input_or_output_class(self.regular_user_1, None, user_workspace, 'xyz', str(uuid.uuid4()), single_resource_input_spec) # handle multiple files where one has an invalid UUID; uuid is fine, # but no Resource multiple_resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': True, 'resource_types': ['MTX', 'I_MTX'] } with self.assertRaises(ValidationError): submitted_input_or_output_class( self.regular_user_1, None, user_workspace, 'xyz', [str(uuid.uuid4()), str(uuid.uuid4())], multiple_resource_input_spec) # handle the case where the UUID identifies a file, but it is not theirs rt = other_user_resource.resource_type single_resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': False, 'resource_types': [ rt, ] } with self.assertRaises(ValidationError): submitted_input_or_output_class(self.regular_user_1, None, user_workspace, 'xyz', str(other_user_resource.id), single_resource_input_spec) # handle the case where the UUID identifies a file, but it is not the correct type r = user_resource_list[0] rt = r.resource_type other_resource_types = [x for x in RESOURCE_MAPPING.keys() if x != rt] single_resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': False, 'resource_types': other_resource_types } with self.assertRaises(ValidationError): submitted_input_or_output_class(self.regular_user_1, None, user_workspace, 'xyz', str(r.id), single_resource_input_spec) # handle the case where we have a list of UUIDs. They all identify # files, but for one of them, it is not the correct type r0 = user_resource_list[0] r1 = user_resource_list[1] rts = [r0.resource_type, r1.resource_type] other_resource_types = [ x for x in RESOURCE_MAPPING.keys() if not x in rts ] resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': True, 'resource_types': other_resource_types } with self.assertRaises(ValidationError): submitted_input_or_output_class( self.regular_user_1, None, user_workspace, 'xyz', [str(r0.id), str(r1.id)], resource_input_spec) # handle the case where we have a list of UUIDs. They all identify # files, but one of them is not in the workspace (it is, however, owned # by the correct user.) r0 = user_resource_list[0] # get the resource_type for r0. Since we are dealing with an input # that expects a single type, we need to now get another, non-workspace # resource with that same type r1_found = False r1 = None idx = 0 while ((not r1_found) and idx < len(non_workspace_resources)): if non_workspace_resources[idx].resource_type == r0.resource_type: r1_found = True r1 = non_workspace_resources[idx] idx += 1 # just a double check rt_set = set([r0.resource_type, r1.resource_type]) if len(rt_set) > 1: raise ImproperlyConfigured( 'Need two resources with the same type where' ' one is in the workspace and the other is not.') resource_input_spec = { 'attribute_type': 'VariableDataResource', 'many': True, 'resource_types': list(rt_set) } with self.assertRaises(ValidationError): submitted_input_or_output_class( self.regular_user_1, None, user_workspace, 'xyz', [str(r0.id), str(r1.id)], resource_input_spec)