/test/functional/test_toolbox.py

https://bitbucket.org/cistrome/cistrome-harvard/ · Python · 117 lines · 76 code · 19 blank · 22 comment · 20 complexity · 8ac68dc0f8873baf6521946d94ad611d MD5 · raw file

  1. import new
  2. import sys
  3. from base.twilltestcase import TwillTestCase
  4. from base.interactor import build_interactor, stage_data_in_history
  5. from galaxy.tools import DataManagerTool
  6. import logging
  7. log = logging.getLogger( __name__ )
  8. toolbox = None
  9. #Do not test Data Managers as part of the standard Tool Test Framework.
  10. TOOL_TYPES_NO_TEST = ( DataManagerTool, )
  11. class ToolTestCase( TwillTestCase ):
  12. """Abstract test case that runs tests based on a `galaxy.tools.test.ToolTest`"""
  13. def do_it( self, testdef ):
  14. """
  15. Run through a tool test case.
  16. """
  17. shed_tool_id = self.shed_tool_id
  18. self._handle_test_def_errors( testdef )
  19. galaxy_interactor = self._galaxy_interactor( testdef )
  20. test_history = galaxy_interactor.new_history()
  21. stage_data_in_history( galaxy_interactor, testdef.test_data(), test_history, shed_tool_id )
  22. data_list = galaxy_interactor.run_tool( testdef, test_history )
  23. self.assertTrue( data_list )
  24. self._verify_outputs( testdef, test_history, shed_tool_id, data_list, galaxy_interactor )
  25. galaxy_interactor.delete_history( test_history )
  26. def _galaxy_interactor( self, testdef ):
  27. return build_interactor( self, testdef.interactor )
  28. def _handle_test_def_errors(self, testdef):
  29. # If the test generation had an error, raise
  30. if testdef.error:
  31. if testdef.exception:
  32. raise testdef.exception
  33. else:
  34. raise Exception( "Test parse failure" )
  35. def _verify_outputs( self, testdef, history, shed_tool_id, data_list, galaxy_interactor ):
  36. maxseconds = testdef.maxseconds
  37. for output_index, output_tuple in enumerate(testdef.outputs):
  38. # Get the correct hid
  39. name, outfile, attributes = output_tuple
  40. try:
  41. output_data = data_list[ name ]
  42. except (TypeError, KeyError):
  43. # Legacy - fall back on ordered data list access if data_list is
  44. # just a list (case with twill variant or if output changes its
  45. # name).
  46. if hasattr(data_list, "values"):
  47. output_data = data_list.values()[ output_index ]
  48. else:
  49. output_data = data_list[ len(data_list) - len(testdef.outputs) + output_index ]
  50. self.assertTrue( output_data is not None )
  51. try:
  52. galaxy_interactor.verify_output( history, output_data, outfile, attributes=attributes, shed_tool_id=shed_tool_id, maxseconds=maxseconds )
  53. except Exception:
  54. for stream in ['stdout', 'stderr']:
  55. stream_output = galaxy_interactor.get_job_stream( history, output_data, stream=stream )
  56. print >>sys.stderr, self._format_stream( stream_output, stream=stream, format=True )
  57. raise
  58. def build_tests( app=None, testing_shed_tools=False, master_api_key=None, user_api_key=None ):
  59. """
  60. If the module level variable `toolbox` is set, generate `ToolTestCase`
  61. classes for all of its tests and put them into this modules globals() so
  62. they can be discovered by nose.
  63. """
  64. if app is None:
  65. return
  66. # Push all the toolbox tests to module level
  67. G = globals()
  68. # Eliminate all previous tests from G.
  69. for key, val in G.items():
  70. if key.startswith( 'TestForTool_' ):
  71. del G[ key ]
  72. for i, tool_id in enumerate( app.toolbox.tools_by_id ):
  73. tool = app.toolbox.get_tool( tool_id )
  74. if isinstance( tool, TOOL_TYPES_NO_TEST ):
  75. #We do not test certain types of tools (e.g. Data Manager tools) as part of ToolTestCase
  76. continue
  77. if tool.tests:
  78. shed_tool_id = None if not testing_shed_tools else tool.id
  79. # Create a new subclass of ToolTestCase, dynamically adding methods
  80. # named test_tool_XXX that run each test defined in the tool config.
  81. name = "TestForTool_" + tool.id.replace( ' ', '_' )
  82. baseclasses = ( ToolTestCase, )
  83. namespace = dict()
  84. for j, testdef in enumerate( tool.tests ):
  85. def make_test_method( td ):
  86. def test_tool( self ):
  87. self.do_it( td )
  88. return test_tool
  89. test_method = make_test_method( testdef )
  90. test_method.__doc__ = "%s ( %s ) > %s" % ( tool.name, tool.id, testdef.name )
  91. namespace[ 'test_tool_%06d' % j ] = test_method
  92. namespace[ 'shed_tool_id' ] = shed_tool_id
  93. namespace[ 'master_api_key' ] = master_api_key
  94. namespace[ 'user_api_key' ] = user_api_key
  95. # The new.classobj function returns a new class object, with name name, derived
  96. # from baseclasses (which should be a tuple of classes) and with namespace dict.
  97. new_class_obj = new.classobj( name, baseclasses, namespace )
  98. G[ name ] = new_class_obj