def test_propmpt(self): """Test generated prompts when reading parameter values from standard input. """ # BOOL p = TemplateParameter( para.set_defaults( para.parameter_declaration(identifier='ABC', data_type=para.DT_BOOL))).prompt() self.assertEqual(p, 'ABC (bool): ') # FILE p = TemplateParameter( para.set_defaults( para.parameter_declaration(identifier='ABC', data_type=para.DT_FILE))).prompt() self.assertEqual(p, 'ABC (filename): ') # FLOAT p = TemplateParameter( para.set_defaults( para.parameter_declaration( identifier='ABC', data_type=para.DT_DECIMAL))).prompt() self.assertEqual(p, 'ABC (decimal): ') # INTEGER p = TemplateParameter( para.set_defaults( para.parameter_declaration( identifier='ABC', data_type=para.DT_INTEGER))).prompt() self.assertEqual(p, 'ABC (integer): ') # STRING p = TemplateParameter( para.set_defaults( para.parameter_declaration( identifier='ABC', data_type=para.DT_STRING))).prompt() self.assertEqual(p, 'ABC (string): ')
def test_file_argument(self): """Test template specifications having file parameters with and without a constant replacement value. """ template = TemplateSpec( workflow_spec={'inputs': { 'files': ['$[[fileA]]', '$[[fileB]]'] }}, parameters=[ pd.parameter_declaration('fileA', data_type=pd.DT_FILE), pd.parameter_declaration('fileB', data_type=pd.DT_FILE, as_const='names.txt') ], validate=True) arguments = { 'fileA': FileHandle('code/Hello.py'), 'fileB': FileHandle('data/inputs.txt') } spec = template.get_workflow_spec(arguments) self.assertEqual(spec['inputs']['files'][0], 'Hello.py') self.assertEqual(spec['inputs']['files'][1], 'names.txt') # Get list of upload files upload_files = template.get_upload_files(arguments) self.assertEqual(len(upload_files), 2) target_files = [fh.target_file for fh in upload_files] self.assertTrue('Hello.py' in target_files) self.assertTrue('names.txt' in target_files) # Value error if we ensure that upload files exist with self.assertRaises(ValueError): template.get_upload_files(arguments, ensure_file_exists=True)
def test_invalid_identifier(self): """Assert that a ValueError is raised if a package declaration with an invalid identifier is given. """ # Ensure that it works with a valid identifier para.parameter_declaration(identifier='ABC', data_type=para.DT_BOOL) # Error is raised if identifier is None with self.assertRaises(ValueError): para.parameter_declaration(identifier=None, data_type=para.DT_BOOL)
def test_duplicate_id(self): """Ensure that exception is raised if parameter identifier are not unique. """ with self.assertRaises(ValueError): TemplateSpec(workflow_spec={}, parameters=[ pd.parameter_declaration('A', index=1), pd.parameter_declaration('B'), pd.parameter_declaration('C'), pd.parameter_declaration('A', index=2), pd.parameter_declaration('E', index=1) ], validate=True)
def test_validate_error(self): """Assert that ValueErrors are raised if an invalid parameter declaration is given to the validate_parameter function. """ pd = para.parameter_declaration(identifier='ABC') # Ensure that creating a dictionary from a valid parameter declaration # is still valid para.validate_parameter(dict(pd)) # Invalid data type for parameter identifier pd_invalid = dict(pd) pd_invalid[para.LABEL_ID] = 123 with self.assertRaises(ValueError): para.validate_parameter(pd_invalid) # Invalid data type for parameter name pd_invalid = dict(pd) pd_invalid[para.LABEL_NAME] = 123 with self.assertRaises(ValueError): para.validate_parameter(pd_invalid) # Invalid data type for parameter data type pd_invalid = dict(pd) pd_invalid[para.LABEL_DATATYPE] = 12.3 with self.assertRaises(ValueError): para.validate_parameter(pd_invalid) # Invalid data type for parameter index pd_invalid = dict(pd) pd_invalid[para.LABEL_INDEX] = '12' with self.assertRaises(ValueError): para.validate_parameter(pd_invalid) # Invalid data type for parameter required pd_invalid = dict(pd) pd_invalid[para.LABEL_REQUIRED] = '12' with self.assertRaises(ValueError): para.validate_parameter(pd_invalid)
def test_sort(self): """Test the sort functionality of the template list_parameters method. """ # Create a new TemplateSpec with an empty workflow specification and # a list of five parameters template = TemplateSpec(workflow_spec={}, parameters=[ pd.parameter_declaration('A', index=1), pd.parameter_declaration('B'), pd.parameter_declaration('C'), pd.parameter_declaration('D', index=2), pd.parameter_declaration('E', index=1) ], validate=True) # Get list of sorted parameter identifier from listing keys = [p.identifier for p in template.list_parameters()] self.assertEqual(keys, ['B', 'C', 'A', 'E', 'D'])
def test_invalid_datatype(self): """Assert that a ValueError is raised if a package declaration with an invalid data type is given. """ # Ensure that it works with a valid data type pd = para.parameter_declaration(identifier='ABC', data_type=para.DT_RECORD) with self.assertRaises(ValueError): pd = para.parameter_declaration(identifier='ABC', data_type='XYZ') # Specifying a non-string value should also raise a ValueError with self.assertRaises(ValueError): para.parameter_declaration(identifier='ABC', data_type=123) # Ensure that validation fails if data type is manipulated pd = para.parameter_declaration(identifier='ABC', data_type=para.DT_RECORD) para.validate_parameter(pd) pd[para.LABEL_DATATYPE] = 'Something unknown' with self.assertRaises(ValueError): para.validate_parameter(pd)
def test_nested_parameters(self): """Test proper nesting of parameters for DT_LIST and DT_RECORD.""" # Create a new TemplateSpec with an empty workflow specification and # a list of six parameters (one record and one list) template = TemplateSpec( workflow_spec={}, parameters=[ pd.parameter_declaration('A'), pd.parameter_declaration('B', data_type=pd.DT_RECORD), pd.parameter_declaration('C', parent='B'), pd.parameter_declaration('D', parent='B'), pd.parameter_declaration('E', data_type=pd.DT_LIST), pd.parameter_declaration('F', parent='E'), ], validate=True) # Parameters 'A', 'C', 'D', and 'F' have no children for key in ['A', 'C', 'D', 'F']: self.assertFalse(template.get_parameter(key).has_children()) # Parameter 'B' has two children 'C' and 'D' b = template.get_parameter('B') self.assertTrue(b.has_children()) self.assertEqual(len(b.children), 2) self.assertTrue('C' in [p.identifier for p in b.children]) self.assertTrue('D' in [p.identifier for p in b.children]) # Parameter 'E' has one childr 'F' e = template.get_parameter('E') self.assertTrue(e.has_children()) self.assertEqual(len(e.children), 1) self.assertTrue('F' in [p.identifier for p in e.children])
def test_template_engine(self): """Test run method of template engine.""" # Create a workflow template template = TemplateSpec( workflow_spec={'inputs': {'files': ['$[[fileA]]', '$[[fileB]]']}}, parameters=[ pd.parameter_declaration('fileA', data_type=pd.DT_FILE), pd.parameter_declaration('fileB', data_type=pd.DT_FILE, as_const='names.txt') ], validate=True ) arguments = { 'fileA': FileHandle('tests/files/template/code/helloworld.py'), 'fileB': FileHandle('tests/files/template/inputs/names.txt') } engine = FakeTemplateEngine() engine.run(template, arguments, 'NAME') self.assertTrue(engine.started) self.assertEqual(len(engine.files), 2) self.assertTrue('helloworld.py' in engine.files) self.assertTrue('names.txt' in engine.files) # Value error when running a workflow with a missing upload file arguments = { 'fileA': FileHandle('Hello.py'), 'fileB': FileHandle('names.txt') } with self.assertRaises(ValueError): engine.run(template, arguments, 'NAME') engine = TemplateEngine() # For completeness test calling the abstract methods with self.assertRaises(NotImplementedError): engine.create_workflow(dict()) with self.assertRaises(NotImplementedError): engine.upload_file('ID', '/dev/null', 'dev/null') with self.assertRaises(NotImplementedError): engine.start_workflow('ID')
def test_maximal_declaration(self): """Test parameter declarations that provide values for all arguments. """ # Set all parameter elements to values that are different from their # default value pd = para.parameter_declaration(identifier='ABC', name='XYZ', description='ABC to XYZ', data_type=para.DT_INTEGER, index=10, required=False, values=[ para.enum_value(value=1), para.enum_value(value=2, text='Two'), para.enum_value(value=3, text='THREE', is_default=True) ], parent='DEF', default_value=5, as_const='data/names.txt') self.assertTrue(isinstance(pd, dict)) self.assertEqual(pd.get(para.LABEL_ID), 'ABC') self.assertEqual(pd.get(para.LABEL_NAME), 'XYZ') self.assertEqual(pd.get(para.LABEL_DESCRIPTION), 'ABC to XYZ') self.assertEqual(pd.get(para.LABEL_DATATYPE), para.DT_INTEGER) self.assertEqual(pd.get(para.LABEL_INDEX), 10) self.assertFalse(pd.get(para.LABEL_REQUIRED)) self.assertEqual(pd.get(para.LABEL_PARENT), 'DEF') self.assertEqual(pd.get(para.LABEL_DEFAULT), 5) self.assertEqual(pd.get(para.LABEL_AS), 'data/names.txt') # Valudate value enumeration values = pd.get(para.LABEL_VALUES, []) self.assertEqual(len(values), 3) self.validate_value(values[0], 1, '1', False) self.validate_value(values[1], 2, 'Two', False) self.validate_value(values[2], 3, 'THREE', True) # Ensure that the returned dictionary is valid with respect to the # parameter schema declaration. para.validate_parameter(pd)
def test_minimal_declaration(self): """Test parameter declarations that only provide the required arguments. """ # Expect to get a dictionary that contains the identifier, name (both # equal to 'ABC'), a data type DT_STRING, an index of 0. The required # flag is True. pd = para.parameter_declaration(identifier='ABC') self.assertTrue(isinstance(pd, dict)) self.assertEqual(pd.get(para.LABEL_ID), 'ABC') self.assertEqual(pd.get(para.LABEL_NAME), 'ABC') self.assertEqual(pd.get(para.LABEL_DESCRIPTION), 'ABC') self.assertEqual(pd.get(para.LABEL_DATATYPE), para.DT_STRING) self.assertEqual(pd.get(para.LABEL_INDEX), 0) self.assertTrue(pd.get(para.LABEL_REQUIRED)) # All other optional elements of the declaration are missing self.assertFalse(para.LABEL_DEFAULT in pd) self.assertFalse(para.LABEL_PARENT in pd) self.assertFalse(para.LABEL_VALUES in pd) # Ensure that the returned dictionary is valid with respect to the # parameter schema declaration. para.validate_parameter(pd)