1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/11028b31d3f0/ Changeset: 11028b31d3f0 User: greg Date: 2013-11-27 21:28:03 Summary: Fixes for the tool shed's install and test framework and enhancements to allow a configurable number of test runs to be stored and displayed. Affected #: 10 files diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 lib/galaxy/webapps/tool_shed/api/repositories.py --- a/lib/galaxy/webapps/tool_shed/api/repositories.py +++ b/lib/galaxy/webapps/tool_shed/api/repositories.py @@ -453,5 +453,7 @@ value_mapper = { 'id' : trans.security.encode_id, 'repository_id' : trans.security.encode_id } if repository_metadata.time_last_tested is not None: - value_mapper[ 'time_last_tested' ] = time_ago + # For some reason the Dictifiable.to_dict() method in ~/galaxy/model/item_attrs.py requires + # a function rather than a mapped value, so just pass the time_ago function here. + value_mapper[ 'time_last_tested' ] = time_ago return value_mapper diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 lib/galaxy/webapps/tool_shed/api/repository_revisions.py --- a/lib/galaxy/webapps/tool_shed/api/repository_revisions.py +++ b/lib/galaxy/webapps/tool_shed/api/repository_revisions.py @@ -166,12 +166,11 @@ repository_metadata = metadata_util.get_repository_metadata_by_id( trans, repository_metadata_id ) flush_needed = False for key, new_value in payload.items(): - if hasattr( repository_metadata, key ): + if key == 'time_last_tested': + repository_metadata.time_last_tested = datetime.datetime.utcnow() + flush_needed = True + elif hasattr( repository_metadata, key ): setattr( repository_metadata, key, new_value ) - if key in [ 'tools_functionally_correct', 'time_last_tested' ]: - # Automatically update repository_metadata.time_last_tested. - repository_metadata.time_last_tested = datetime.datetime.utcnow() - flush_needed = True flush_needed = True if flush_needed: trans.sa_session.add( repository_metadata ) @@ -192,5 +191,7 @@ value_mapper = { 'id' : trans.security.encode_id, 'repository_id' : trans.security.encode_id } if repository_metadata.time_last_tested is not None: + # For some reason the Dictifiable.to_dict() method in ~/galaxy/model/item_attrs.py requires + # a function rather than a mapped value, so just pass the time_ago function here. value_mapper[ 'time_last_tested' ] = time_ago return value_mapper diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 lib/galaxy/webapps/tool_shed/config.py --- a/lib/galaxy/webapps/tool_shed/config.py +++ b/lib/galaxy/webapps/tool_shed/config.py @@ -53,6 +53,8 @@ self.tool_data_table_config_path = resolve_path( kwargs.get( 'tool_data_table_config_path', 'tool_data_table_conf.xml' ), self.root ) self.shed_tool_data_table_config = resolve_path( kwargs.get( 'shed_tool_data_table_config', 'shed_tool_data_table_conf.xml' ), self.root ) self.ftp_upload_dir = kwargs.get( 'ftp_upload_dir', None ) + # Install and test framework for testing tools contained in repositories. + self.num_tool_test_results_saved = kwargs.get( 'num_tool_test_results_saved', 5 ) # Location for dependencies if 'tool_dependency_dir' in kwargs: self.tool_dependency_dir = resolve_path( kwargs.get( "tool_dependency_dir" ), self.root ) diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 lib/galaxy/webapps/tool_shed/controllers/repository.py --- a/lib/galaxy/webapps/tool_shed/controllers/repository.py +++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py @@ -1515,51 +1515,59 @@ tool_shed_url = web.url_for( '/', qualified=True ) functional_test_results = [] - for metadata_row in trans.sa_session.query( trans.model.RepositoryMetadata ) \ + for repository_metadata in trans.sa_session.query( trans.model.RepositoryMetadata ) \ .filter( metadata_filter ) \ .join( trans.model.Repository ) \ .filter( and_( trans.model.Repository.table.c.deleted == False, trans.model.Repository.table.c.private == False, trans.model.Repository.table.c.deprecated == False, trans.model.Repository.table.c.user_id == user.id ) ): - if not metadata_row.tool_test_results: - continue - if metadata_row.changeset_revision != metadata_row.repository.tip( trans.app ): - continue - current_repository_errors = [] - tool_dependency_errors = [] - repository_dependency_errors = [] - description_lines = [] - # Per the RSS 2.0 specification, all dates in RSS feeds must be formatted as specified in RFC 822 - # section 5.1, e.g. Sat, 07 Sep 2002 00:00:01 UT - time_tested = metadata_row.time_last_tested.strftime( '%a, %d %b %Y %H:%M:%S UT' ) - repository = metadata_row.repository - # Generate a citable URL for this repository with owner and changeset revision. - repository_citable_url = suc.url_join( tool_shed_url, 'view', user.username, repository.name, metadata_row.changeset_revision ) - passed_tests = len( metadata_row.tool_test_results.get( 'passed_tests', [] ) ) - failed_tests = len( metadata_row.tool_test_results.get( 'failed_tests', [] ) ) - missing_test_components = len( metadata_row.tool_test_results.get( 'missing_test_components', [] ) ) - installation_errors = metadata_row.tool_test_results.get( 'installation_errors', [] ) - if installation_errors: - tool_dependency_errors = installation_errors.get( 'tool_dependencies', [] ) - repository_dependency_errors = installation_errors.get( 'repository_dependencies', [] ) - current_repository_errors = installation_errors.get( 'current_repository', [] ) - description_lines.append( '%d tests passed, %d tests failed, %d tests missing test components.' % \ - ( passed_tests, failed_tests, missing_test_components ) ) - if current_repository_errors: - description_lines.append( '\nThis repository did not install correctly. ' ) - if tool_dependency_errors or repository_dependency_errors: - description_lines.append( '\n%d tool dependencies and %d repository dependencies failed to install. ' % \ - ( len( tool_dependency_errors ), len( repository_dependency_errors ) ) ) - title = 'Revision %s of %s' % ( metadata_row.changeset_revision, repository.name ) - # The guid attribute in an RSS feed's list of items allows a feed reader to choose not to show an item as updated - # if the guid is unchanged. For functional test results, the citable URL is sufficiently unique to enable - # that behavior. - functional_test_results.append( dict( title=title, - guid=repository_citable_url, - link=repository_citable_url, - description='\n'.join( description_lines ), - pubdate=time_tested ) ) + repository = repository_metadata.repository + repo_dir = repository.repo_path( trans.app ) + repo = hg.repository( suc.get_configured_ui(), repo_dir ) + latest_downloadable_changeset_revsion = suc.get_latest_downloadable_changeset_revision( trans, repository, repo ) + if repository_metadata.changeset_revision == latest_downloadable_changeset_revsion: + # We'll display only the test run for the latest installable revision in the rss feed. + tool_test_results = repository_metadata.tool_test_results + if tool_test_results is not None: + # The tool_test_results column used to contain a single dictionary, but was recently enhanced to contain + # a list of dictionaries, one for each install and test run. We'll display only the latest run in the rss + # feed for nwo. + if isinstance( tool_test_results, list ): + tool_test_results = tool_test_results[ 0 ] + current_repository_errors = [] + tool_dependency_errors = [] + repository_dependency_errors = [] + description_lines = [] + # Per the RSS 2.0 specification, all dates in RSS feeds must be formatted as specified in RFC 822 + # section 5.1, e.g. Sat, 07 Sep 2002 00:00:01 UT + time_tested = repository_metadata.time_last_tested.strftime( '%a, %d %b %Y %H:%M:%S UT' ) + # Generate a citable URL for this repository with owner and changeset revision. + repository_citable_url = suc.url_join( tool_shed_url, 'view', user.username, repository.name, repository_metadata.changeset_revision ) + passed_tests = len( tool_test_results.get( 'passed_tests', [] ) ) + failed_tests = len( tool_test_results.get( 'failed_tests', [] ) ) + missing_test_components = len( tool_test_results.get( 'missing_test_components', [] ) ) + installation_errors = tool_test_results.get( 'installation_errors', [] ) + if installation_errors: + tool_dependency_errors = installation_errors.get( 'tool_dependencies', [] ) + repository_dependency_errors = installation_errors.get( 'repository_dependencies', [] ) + current_repository_errors = installation_errors.get( 'current_repository', [] ) + description_lines.append( '%d tests passed, %d tests failed, %d tests missing test components.' % \ + ( passed_tests, failed_tests, missing_test_components ) ) + if current_repository_errors: + description_lines.append( '\nThis repository did not install correctly. ' ) + if tool_dependency_errors or repository_dependency_errors: + description_lines.append( '\n%d tool dependencies and %d repository dependencies failed to install. ' % \ + ( len( tool_dependency_errors ), len( repository_dependency_errors ) ) ) + title = 'Revision %s of %s' % ( repository_metadata.changeset_revision, repository.name ) + # The guid attribute in an RSS feed's list of items allows a feed reader to choose not to show an item as updated + # if the guid is unchanged. For functional test results, the citable URL is sufficiently unique to enable + # that behavior. + functional_test_results.append( dict( title=title, + guid=repository_citable_url, + link=repository_citable_url, + description='\n'.join( description_lines ), + pubdate=time_tested ) ) trans.response.set_content_type( 'application/rss+xml' ) return trans.fill_template( '/rss.mako', title='Tool functional test results', diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 lib/galaxy/webapps/tool_shed/model/__init__.py --- a/lib/galaxy/webapps/tool_shed/model/__init__.py +++ b/lib/galaxy/webapps/tool_shed/model/__init__.py @@ -229,11 +229,14 @@ class RepositoryMetadata( object, Dictifiable ): - dict_collection_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'malicious', 'downloadable', 'has_repository_dependencies', 'includes_datatypes', - 'includes_tools', 'includes_tool_dependencies', 'includes_tools_for_display_in_tool_panel', 'includes_workflows', 'time_last_tested' ) - dict_element_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'malicious', 'downloadable', 'tools_functionally_correct', 'do_not_test', - 'test_install_error', 'time_last_tested', 'tool_test_results', 'has_repository_dependencies', 'includes_datatypes', - 'includes_tools', 'includes_tool_dependencies', 'includes_tools_for_display_in_tool_panel', 'includes_workflows' ) + dict_collection_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'malicious', 'downloadable', 'missing_test_components', + 'tools_functionally_correct', 'do_not_test', 'test_install_error', 'has_repository_dependencies', + 'includes_datatypes', 'includes_tools', 'includes_tool_dependencies', 'includes_tools_for_display_in_tool_panel', + 'includes_workflows', 'time_last_tested' ) + dict_element_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'malicious', 'downloadable', 'missing_test_components', + 'tools_functionally_correct', 'do_not_test', 'test_install_error', 'time_last_tested', 'tool_test_results', + 'has_repository_dependencies', 'includes_datatypes', 'includes_tools', 'includes_tool_dependencies', + 'includes_tools_for_display_in_tool_panel', 'includes_workflows' ) def __init__( self, id=None, repository_id=None, changeset_revision=None, metadata=None, tool_versions=None, malicious=False, downloadable=False, missing_test_components=None, tools_functionally_correct=False, do_not_test=False, test_install_error=False, time_last_tested=None, @@ -242,8 +245,8 @@ self.id = id self.repository_id = repository_id self.changeset_revision = changeset_revision - self.metadata = metadata or dict() - self.tool_versions = tool_versions or dict() + self.metadata = metadata + self.tool_versions = tool_versions self.malicious = malicious self.downloadable = downloadable self.missing_test_components = missing_test_components @@ -251,7 +254,7 @@ self.do_not_test = do_not_test self.test_install_error = test_install_error self.time_last_tested = time_last_tested - self.tool_test_results = tool_test_results or dict() + self.tool_test_results = tool_test_results self.has_repository_dependencies = has_repository_dependencies # We don't consider the special case has_repository_dependencies_only_if_compiling_contained_td here. self.includes_datatypes = includes_datatypes diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 lib/tool_shed/scripts/api/common.py --- a/lib/tool_shed/scripts/api/common.py +++ b/lib/tool_shed/scripts/api/common.py @@ -158,7 +158,7 @@ print e.read( 1024 ) sys.exit( 1 ) else: - return 'Error. '+ str( e.read( 1024 ) ) + return 'Error. ' + str( e.read( 1024 ) ) if not return_formatted: return r print 'Response' diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 lib/tool_shed/scripts/check_repositories_for_functional_tests.py --- a/lib/tool_shed/scripts/check_repositories_for_functional_tests.py +++ b/lib/tool_shed/scripts/check_repositories_for_functional_tests.py @@ -25,6 +25,7 @@ from galaxy.model.orm import and_ from galaxy.model.orm import not_ from galaxy.model.orm import select +from galaxy.util import listify from mercurial import hg from mercurial import ui from mercurial import __version__ @@ -41,16 +42,17 @@ """Application that enables updating repository_metadata table records in the Tool Shed.""" def __init__( self, config ): - if config.database_connection is False: - config.database_connection = "sqlite:///%s?isolation_level=IMMEDIATE" % str( config.database ) - log.debug( 'Using database connection: %s' % str( config.database_connection ) ) + self.config = config + if self.config.database_connection is False: + self.config.database_connection = "sqlite:///%s?isolation_level=IMMEDIATE" % str( config.database ) + log.debug( 'Using database connection: %s' % str( self.config.database_connection ) ) # Setup the database engine and ORM - self.model = galaxy.webapps.tool_shed.model.mapping.init( config.file_path, - config.database_connection, + self.model = galaxy.webapps.tool_shed.model.mapping.init( self.config.file_path, + self.config.database_connection, engine_options={}, create_tables=False ) self.hgweb_config_manager = self.model.hgweb_config_manager - self.hgweb_config_manager.hgweb_config_dir = config.hgweb_config_dir + self.hgweb_config_manager.hgweb_config_dir = self.config.hgweb_config_dir log.debug( 'Using hgweb.config file: %s' % str( self.hgweb_config_manager.hgweb_config ) ) @property @@ -72,19 +74,7 @@ "id": "tool_wrapper", "name": "Map with Tool Wrapper", "requirements": [], - "tests": [ - { - "inputs": [ [ "parameter", "value" ], [ "other_parameter", "other_value" ], ], - "name": "Test-1", - "outputs": [ - [ - "output_field_name", - "output_file_name.bed" - ] - ], - "required_files": [ '1.bed', '2.bed', '3.bed' ] - } - ], + "tests": [], "tool_config": "database/community_files/000/repo_1/tool_wrapper.xml", "tool_type": "default", "version": "1.2.3", @@ -120,11 +110,6 @@ missing_test_components = [] repository = repository_metadata.repository records_checked += 1 - # Create the tool_test_results_dict dictionary, using the dictionary from the previous test run if available. - if repository_metadata.tool_test_results: - tool_test_results_dict = repository_metadata.tool_test_results - else: - tool_test_results_dict = {} # Check the next repository revision. changeset_revision = str( repository_metadata.changeset_revision ) name = repository.name @@ -141,7 +126,7 @@ tool_dicts = metadata.get( 'tools', None ) if tool_dicts is not None: has_test_data = False - testable_revision_found = False + testable_revision = False # Clone the repository up to the changeset revision we're checking. repo_dir = repository.repo_path( app ) repo = hg.repository( get_configured_ui(), repo_dir ) @@ -236,7 +221,7 @@ if test_errors not in missing_test_components: missing_test_components.append( test_errors ) if tool_has_tests and has_test_files: - testable_revision_found = True + testable_revision = True # Remove the cloned repository path. This has to be done after the check for required test files, for obvious reasons. if os.path.exists( work_dir ): shutil.rmtree( work_dir ) @@ -253,6 +238,27 @@ if 'missing_components' in invalid_test: print '# %s' % invalid_test[ 'missing_components' ] if not info_only: + # Get or create the list of tool_test_results dictionaries. + if repository_metadata.tool_test_results is not None: + # We'll listify the column value in case it uses the old approach of storing the results of only a single test run. + tool_test_results_dicts = listify( repository_metadata.tool_test_results ) + else: + tool_test_results_dicts = [] + if tool_test_results_dicts: + # Inspect the tool_test_results_dict for the last test run in case it contains only a test_environment + # entry. This will occur with multiple runs of this script without running the associated + # install_and_test_tool_sed_repositories.sh script which will further populate the tool_test_results_dict. + tool_test_results_dict = tool_test_results_dicts[ 0 ] + if len( tool_test_results_dict ) <= 1: + # We can re-use the mostly empty tool_test_results_dict for this run, but we need to eliminate it from + # the list of tool_test_results_dicts since it will be re-inserted later. + tool_test_results_dict = tool_test_results_dicts.pop( 0 ) + else: + # The latest tool_test_results_dict has been populated with the results of a test run, so it cannot be used. + tool_test_results_dict = {} + else: + # Create a new dictionary for the most recent test run. + tool_test_results_dict = {} test_environment_dict = tool_test_results_dict.get( 'test_environment', {} ) test_environment_dict[ 'tool_shed_database_version' ] = get_database_version( app ) test_environment_dict[ 'tool_shed_mercurial_version' ] = __version__.version @@ -270,12 +276,24 @@ # changeset revision will be created, either of which will be automatically checked and flagged as appropriate. # In the install and test script, this behavior is slightly different, since we do want to always run functional # tests on the most recent downloadable changeset revision. - if should_set_do_not_test_flag( app, repository_metadata.repository, changeset_revision ) and not testable_revision_found: + if should_set_do_not_test_flag( app, repository, changeset_revision, testable_revision ): + print "# Setting do_not_test to True on revision %s of repository %s because it is missing test components" % \ + ( changeset_revision, name ) + print "# and it is not the latest downloadable revision." repository_metadata.do_not_test = True repository_metadata.tools_functionally_correct = False repository_metadata.missing_test_components = True tool_test_results_dict[ 'missing_test_components' ] = missing_test_components - repository_metadata.tool_test_results = tool_test_results_dict + # Store only the configured number of test runs. + num_tool_test_results_saved = int( app.config.num_tool_test_results_saved ) + if len( tool_test_results_dicts ) >= num_tool_test_results_saved: + test_results_index = num_tool_test_results_saved - 1 + new_tool_test_results_dicts = tool_test_results_dicts[ :test_results_index ] + else: + new_tool_test_results_dicts = [ d for d in tool_test_results_dicts ] + # Insert the new element into the first position in the list. + new_tool_test_results_dicts.insert( 0, tool_test_results_dict ) + repository_metadata.tool_test_results = new_tool_test_results_dicts app.sa_session.add( repository_metadata ) app.sa_session.flush() stop = time.time() @@ -313,19 +331,6 @@ changelog_tuples.append( ( ctx.rev(), str( ctx ) ) ) return changelog_tuples -def is_most_recent_downloadable_revision( app, repository, changeset_revision, downloadable_revisions ): - # Get a list of ( numeric revision, changeset hash ) tuples from the changelog. - changelog = get_repo_changelog_tuples( repository.repo_path( app ) ) - latest_downloadable_revision = None - for ctx_rev, changeset_hash in changelog: - if changeset_hash in downloadable_revisions: - # The last changeset hash in the changelog that is present in the list of downloadable revisions will always be the most - # recent downloadable revision, since the changelog tuples are ordered from earliest to most recent. - latest_downloadable_revision = changeset_hash - if latest_downloadable_revision == changeset_revision: - return True - return False - def main(): '''Script that checks repositories to see if the tools contained within them have functional tests defined.''' parser = OptionParser() @@ -345,7 +350,7 @@ config_parser.read( ini_file ) config_dict = {} for key, value in config_parser.items( "app:main" ): - config_dict[key] = value + config_dict[ key ] = value config = tool_shed_config.Configuration( **config_dict ) config_section = options.section now = strftime( "%Y-%m-%d %H:%M:%S" ) @@ -361,34 +366,27 @@ print "# Displaying extra information ( --verbosity = %d )" % options.verbosity check_and_update_repository_metadata( app, info_only=options.info_only, verbosity=options.verbosity ) -def should_set_do_not_test_flag( app, repository, changeset_revision ): - ''' - Returns True if: - a) There are multiple downloadable revisions, and the provided changeset revision is not the most recent downloadable revision. In this case, - the revision will never be updated with correct data, and re-testing it would be redundant. - b) There are one or more downloadable revisions, and the provided changeset revision is the most recent downloadable revision. In this case, if - the repository is updated with test data or functional tests, the downloadable changeset revision that was tested will either be replaced - with the new changeset revision, or a new downloadable changeset revision will be created, either of which will be automatically checked and - flagged as appropriate. In the install and test script, this behavior is slightly different, since we do want to always run functional tests - on the most recent downloadable changeset revision. - ''' - repository_revisions = app.sa_session.query( app.model.RepositoryMetadata ) \ - .filter( and_( app.model.RepositoryMetadata.table.c.downloadable == True, - app.model.RepositoryMetadata.table.c.repository_id == repository.id ) ) \ - .all() - downloadable_revisions = [ repository_metadata.changeset_revision for repository_metadata in repository_revisions ] - is_latest_revision = is_most_recent_downloadable_revision( app, repository, changeset_revision, downloadable_revisions ) - if len( downloadable_revisions ) == 1: - return True - elif len( downloadable_revisions ) > 1 and is_latest_revision: - return True - elif len( downloadable_revisions ) > 1 and not is_latest_revision: - return True - else: - return False +def should_set_do_not_test_flag( app, repository, changeset_revision, testable_revision ): + """ + The received testable_revision is True if the tool has defined tests and test files are in the repository + This method returns True if the received repository has multiple downloadable revisions and the received + changeset_revision is not the most recent downloadable revision and the received testable_revision is False. + In this case, the received changeset_revision will never be updated with correct data, and re-testing it + would be redundant. + """ + if not testable_revision: + repo_dir = repository.repo_path( app ) + repo = hg.repository( suc.get_configured_ui(), repo_dir ) + changeset_revisions = suc.get_ordered_metadata_changeset_revisions( repository, repo, downloadable=True ) + if len( changeset_revisions ) > 1: + latest_downloadable_revision = changeset_revisions[ -1 ] + if changeset_revision != latest_downloadable_revision: + return True + return False if __name__ == "__main__": - # The repository_metadata.tool_test_results json value should have the following structure: + # The repository_metadata.tool_test_results json value should have the following list structure: + # [ # { # "test_environment": # { @@ -467,6 +465,7 @@ # }, # ] # } + # ] # # Optionally, "traceback" may be included in a test_errors dict, if it is relevant. No script should overwrite anything other # than the list relevant to what it is testing. diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 lib/tool_shed/util/container_util.py --- a/lib/tool_shed/util/container_util.py +++ b/lib/tool_shed/util/container_util.py @@ -1,7 +1,7 @@ import logging import os import threading -from galaxy.util import asbool +import galaxy.util from galaxy.web.framework.helpers import time_ago from tool_shed.util import common_util from tool_shed.util import readme_util @@ -72,8 +72,8 @@ repository_name=name, repository_owner=owner, changeset_revision=changeset_revision, - prior_installation_required=asbool( prior_installation_required ), - only_if_compiling_contained_td=asbool( only_if_compiling_contained_td ) ) + prior_installation_required=galaxy.util.asbool( prior_installation_required ), + only_if_compiling_contained_td=galaxy.util.asbool( only_if_compiling_contained_td ) ) class DataManager( object ): @@ -497,8 +497,8 @@ repository_name=name, repository_owner=owner, changeset_revision=changeset_revision, - prior_installation_required=asbool( prior_installation_required ), - only_if_compiling_contained_td=asbool( only_if_compiling_contained_td ), + prior_installation_required=galaxy.util.asbool( prior_installation_required ), + only_if_compiling_contained_td=galaxy.util.asbool( only_if_compiling_contained_td ), error=error ) folder.invalid_repository_dependencies.append( ird ) invalid_repository_dependencies_folder.folders.append( folder ) @@ -831,16 +831,12 @@ label='Valid tools' ) containers_dict[ 'valid_tools' ] = valid_tools_root_folder # Tool test results container. - tool_test_results = repository_metadata.tool_test_results + tool_test_results = galaxy.util.listify( repository_metadata.tool_test_results ) # Only create and populate this folder if there are actual tool test results to display. if can_display_tool_test_results( tool_test_results, exclude=exclude ): - time_tested = repository_metadata.time_last_tested - if time_tested is not None: - time_tested = time_ago( time_tested ) folder_id, tool_test_results_root_folder = build_tool_test_results_folder( trans, folder_id, tool_test_results, - time_tested, label='Tool test results' ) containers_dict[ 'tool_test_results' ] = tool_test_results_root_folder # Workflows container. @@ -1052,153 +1048,165 @@ tool_dependencies_root_folder = None return folder_id, tool_dependencies_root_folder -def build_tool_test_results_folder( trans, folder_id, tool_test_results_dict, time_tested, label='Tool test results' ): +def build_tool_test_results_folder( trans, folder_id, tool_test_results_dicts, label='Tool test results' ): """Return a folder hierarchy containing tool dependencies.""" # This container is displayed only in the tool shed. - if tool_test_results_dict: + if tool_test_results_dicts: + multiple_tool_test_results_dicts = len( tool_test_results_dicts ) > 1 + test_results_dict_id = 0 folder_id += 1 tool_test_results_root_folder = Folder( id=folder_id, key='root', label='root', parent=None ) - test_environment_dict = tool_test_results_dict.get( 'test_environment', None ) - if test_environment_dict is not None: - folder_id += 1 - test_results_folder = Folder( id=folder_id, key='test_results', label=label, parent=tool_test_results_root_folder ) - tool_test_results_root_folder.folders.append( test_results_folder ) - folder_id += 1 - folder = Folder( id=folder_id, key='test_environment', label='Automated test environment', parent=test_results_folder ) - test_results_folder.folders.append( folder ) - architecture = test_environment_dict.get( 'architecture', '' ) - galaxy_database_version = test_environment_dict.get( 'galaxy_database_version', '' ) - galaxy_revision = test_environment_dict.get( 'galaxy_revision', '' ) - python_version = test_environment_dict.get( 'python_version', '' ) - system = test_environment_dict.get( 'system', '' ) - time_tested = time_tested - tool_shed_database_version = test_environment_dict.get( 'tool_shed_database_version', '' ) - tool_shed_mercurial_version = test_environment_dict.get( 'tool_shed_mercurial_version', '' ) - tool_shed_revision = test_environment_dict.get( 'tool_shed_revision', '' ) - test_environment = TestEnvironment( id=1, - architecture=architecture, - galaxy_database_version=galaxy_database_version, - galaxy_revision=galaxy_revision, - python_version=python_version, - system=system, - time_tested=time_tested, - tool_shed_database_version=tool_shed_database_version, - tool_shed_mercurial_version=tool_shed_mercurial_version, - tool_shed_revision=tool_shed_revision ) - folder.test_environments.append( test_environment ) - not_tested_dict = tool_test_results_dict.get( 'not_tested', {} ) - if not_tested_dict: - folder_id += 1 - folder = Folder( id=folder_id, key='not_tested', label='Not tested', parent=test_results_folder ) - test_results_folder.folders.append( folder ) - not_tested_id = 0 - not_tested = NotTested( id=not_tested_id, - reason=not_tested_dict.get( 'reason', '' ) ) - folder.not_tested.append( not_tested ) - passed_tests_dicts = tool_test_results_dict.get( 'passed_tests', [] ) - if passed_tests_dicts: - folder_id += 1 - folder = Folder( id=folder_id, key='passed_tests', label='Tests that passed successfully', parent=test_results_folder ) - test_results_folder.folders.append( folder ) - passed_test_id = 0 - for passed_tests_dict in passed_tests_dicts: - passed_test_id += 1 - passed_test = PassedTest( id=passed_test_id, - test_id=passed_tests_dict.get( 'test_id' '' ), - tool_id=passed_tests_dict.get( 'tool_id', '' ), - tool_version=passed_tests_dict.get( 'tool_version', '' ) ) - folder.passed_tests.append( passed_test ) - failed_tests_dicts = tool_test_results_dict.get( 'failed_tests', [] ) - if failed_tests_dicts: - folder_id += 1 - folder = Folder( id=folder_id, key='failed_tests', label='Tests that failed', parent=test_results_folder ) - test_results_folder.folders.append( folder ) - failed_test_id = 0 - for failed_tests_dict in failed_tests_dicts: - failed_test_id += 1 - failed_test = FailedTest( id=failed_test_id, - stderr=failed_tests_dict.get( 'stderr', '' ), - test_id=failed_tests_dict.get( 'test_id', '' ), - tool_id=failed_tests_dict.get( 'tool_id', '' ), - tool_version=failed_tests_dict.get( 'tool_version', '' ), - traceback=failed_tests_dict.get( 'traceback', '' ) ) - folder.failed_tests.append( failed_test ) - missing_test_components_dicts = tool_test_results_dict.get( 'missing_test_components', [] ) - if missing_test_components_dicts: - folder_id += 1 - folder = Folder( id=folder_id, key='missing_test_components', label='Tools missing tests or test data', parent=test_results_folder ) - test_results_folder.folders.append( folder ) - missing_test_component_id = 0 - for missing_test_components_dict in missing_test_components_dicts: - missing_test_component_id += 1 - missing_test_component = MissingTestComponent( id=missing_test_component_id, - missing_components=missing_test_components_dict.get( 'missing_components', '' ), - tool_guid=missing_test_components_dict.get( 'tool_guid', '' ), - tool_id=missing_test_components_dict.get( 'tool_id', '' ), - tool_version=missing_test_components_dict.get( 'tool_version', '' ) ) - folder.missing_test_components.append( missing_test_component ) - installation_error_dicts = tool_test_results_dict.get( 'installation_errors', {} ) - if installation_error_dicts: - current_repository_errors = installation_error_dicts.get( 'current_repository', [] ) - repository_dependency_errors = installation_error_dicts.get( 'repository_dependencies', [] ) - tool_dependency_errors = installation_error_dicts.get( 'tool_dependencies', [] ) - if current_repository_errors or repository_dependency_errors or tool_dependency_errors: + for index, tool_test_results_dict in enumerate( tool_test_results_dicts ): + test_environment_dict = tool_test_results_dict.get( 'test_environment', None ) + if test_environment_dict is not None: + time_tested = test_environment_dict.get( 'time_tested', 'unknown_%d' % index ) + if multiple_tool_test_results_dicts: + folder_id += 1 + containing_folder = Folder( id=folder_id, key='test_results', label=time_tested, parent=tool_test_results_root_folder ) + else: + containing_folder = tool_test_results_root_folder + test_results_dict_id += 1 + #folder_id += 1 + #test_results_folder = Folder( id=folder_id, key='test_results', label='Automated test environment', parent=containing_folder ) + #containing_folder.folders.append( test_results_folder ) folder_id += 1 - installation_error_base_folder = Folder( id=folder_id, - key='installation_errors', - label='Installation errors', - parent=test_results_folder ) - if current_repository_errors: + folder = Folder( id=folder_id, key='test_environment', label='Automated test environment', parent=containing_folder ) + containing_folder.folders.append( folder ) + architecture = test_environment_dict.get( 'architecture', '' ) + galaxy_database_version = test_environment_dict.get( 'galaxy_database_version', '' ) + galaxy_revision = test_environment_dict.get( 'galaxy_revision', '' ) + python_version = test_environment_dict.get( 'python_version', '' ) + system = test_environment_dict.get( 'system', '' ) + tool_shed_database_version = test_environment_dict.get( 'tool_shed_database_version', '' ) + tool_shed_mercurial_version = test_environment_dict.get( 'tool_shed_mercurial_version', '' ) + tool_shed_revision = test_environment_dict.get( 'tool_shed_revision', '' ) + test_environment = TestEnvironment( id=1, + architecture=architecture, + galaxy_database_version=galaxy_database_version, + galaxy_revision=galaxy_revision, + python_version=python_version, + system=system, + time_tested=time_tested, + tool_shed_database_version=tool_shed_database_version, + tool_shed_mercurial_version=tool_shed_mercurial_version, + tool_shed_revision=tool_shed_revision ) + folder.test_environments.append( test_environment ) + not_tested_dict = tool_test_results_dict.get( 'not_tested', {} ) + if not_tested_dict: + folder_id += 1 + folder = Folder( id=folder_id, key='not_tested', label='Not tested', parent=containing_folder ) + containing_folder.folders.append( folder ) + not_tested_id = 0 + not_tested = NotTested( id=not_tested_id, + reason=not_tested_dict.get( 'reason', '' ) ) + folder.not_tested.append( not_tested ) + passed_tests_dicts = tool_test_results_dict.get( 'passed_tests', [] ) + if passed_tests_dicts: + folder_id += 1 + folder = Folder( id=folder_id, key='passed_tests', label='Tests that passed successfully', parent=containing_folder ) + containing_folder.folders.append( folder ) + passed_test_id = 0 + for passed_tests_dict in passed_tests_dicts: + passed_test_id += 1 + passed_test = PassedTest( id=passed_test_id, + test_id=passed_tests_dict.get( 'test_id' '' ), + tool_id=passed_tests_dict.get( 'tool_id', '' ), + tool_version=passed_tests_dict.get( 'tool_version', '' ) ) + folder.passed_tests.append( passed_test ) + failed_tests_dicts = tool_test_results_dict.get( 'failed_tests', [] ) + if failed_tests_dicts: + folder_id += 1 + folder = Folder( id=folder_id, key='failed_tests', label='Tests that failed', parent=containing_folder ) + containing_folder.folders.append( folder ) + failed_test_id = 0 + for failed_tests_dict in failed_tests_dicts: + failed_test_id += 1 + failed_test = FailedTest( id=failed_test_id, + stderr=failed_tests_dict.get( 'stderr', '' ), + test_id=failed_tests_dict.get( 'test_id', '' ), + tool_id=failed_tests_dict.get( 'tool_id', '' ), + tool_version=failed_tests_dict.get( 'tool_version', '' ), + traceback=failed_tests_dict.get( 'traceback', '' ) ) + folder.failed_tests.append( failed_test ) + missing_test_components_dicts = tool_test_results_dict.get( 'missing_test_components', [] ) + if missing_test_components_dicts: + folder_id += 1 + folder = Folder( id=folder_id, key='missing_test_components', label='Tools missing tests or test data', parent=containing_folder ) + containing_folder.folders.append( folder ) + missing_test_component_id = 0 + for missing_test_components_dict in missing_test_components_dicts: + missing_test_component_id += 1 + missing_test_component = MissingTestComponent( id=missing_test_component_id, + missing_components=missing_test_components_dict.get( 'missing_components', '' ), + tool_guid=missing_test_components_dict.get( 'tool_guid', '' ), + tool_id=missing_test_components_dict.get( 'tool_id', '' ), + tool_version=missing_test_components_dict.get( 'tool_version', '' ) ) + folder.missing_test_components.append( missing_test_component ) + installation_error_dicts = tool_test_results_dict.get( 'installation_errors', {} ) + if installation_error_dicts: + current_repository_errors = installation_error_dicts.get( 'current_repository', [] ) + repository_dependency_errors = installation_error_dicts.get( 'repository_dependencies', [] ) + tool_dependency_errors = installation_error_dicts.get( 'tool_dependencies', [] ) + if current_repository_errors or repository_dependency_errors or tool_dependency_errors: folder_id += 1 - subfolder = Folder( id=folder_id, - key='current_repository_errors', - label='This repository', - parent=installation_error_base_folder ) - repository_error_id = 0 - for repository_error_dict in current_repository_errors: - repository_error_id += 1 - repository_installation_error = RepositoryInstallationError( id=repository_error_id, - tool_shed=repository_error_dict.get( 'tool_shed', '' ), - name=repository_error_dict.get( 'name', '' ), - owner=repository_error_dict.get( 'owner', '' ), - changeset_revision=repository_error_dict.get( 'changeset_revision', '' ), - error_message=repository_error_dict.get( 'error_message', '' ) ) - subfolder.current_repository_installation_errors.append( repository_installation_error ) - installation_error_base_folder.folders.append( subfolder ) - if repository_dependency_errors: - folder_id += 1 - subfolder = Folder( id=folder_id, - key='repository_dependency_errors', - label='Repository dependencies', - parent=installation_error_base_folder ) - repository_error_id = 0 - for repository_error_dict in repository_dependency_errors: - repository_error_id += 1 - repository_installation_error = RepositoryInstallationError( id=repository_error_id, - tool_shed=repository_error_dict.get( 'tool_shed', '' ), - name=repository_error_dict.get( 'name', '' ), - owner=repository_error_dict.get( 'owner', '' ), - changeset_revision=repository_error_dict.get( 'changeset_revision', '' ), - error_message=repository_error_dict.get( 'error_message', '' ) ) - subfolder.repository_installation_errors.append( repository_installation_error ) - installation_error_base_folder.folders.append( subfolder ) - if tool_dependency_errors: - folder_id += 1 - subfolder = Folder( id=folder_id, - key='tool_dependency_errors', - label='Tool dependencies', - parent=installation_error_base_folder ) - tool_dependency_error_id = 0 - for tool_dependency_error_dict in tool_dependency_errors: - tool_dependency_error_id += 1 - tool_dependency_installation_error = ToolDependencyInstallationError( id=tool_dependency_error_id, - type=tool_dependency_error_dict.get( 'type', '' ), - name=tool_dependency_error_dict.get( 'name', '' ), - version=tool_dependency_error_dict.get( 'version', '' ), - error_message=tool_dependency_error_dict.get( 'error_message', '' ) ) - subfolder.tool_dependency_installation_errors.append( tool_dependency_installation_error ) - installation_error_base_folder.folders.append( subfolder ) - test_results_folder.installation_errors.append( installation_error_base_folder ) + installation_error_base_folder = Folder( id=folder_id, + key='installation_errors', + label='Installation errors', + parent=containing_folder ) + if current_repository_errors: + folder_id += 1 + subfolder = Folder( id=folder_id, + key='current_repository_errors', + label='This repository', + parent=installation_error_base_folder ) + repository_error_id = 0 + for repository_error_dict in current_repository_errors: + repository_error_id += 1 + repository_installation_error = RepositoryInstallationError( id=repository_error_id, + tool_shed=repository_error_dict.get( 'tool_shed', '' ), + name=repository_error_dict.get( 'name', '' ), + owner=repository_error_dict.get( 'owner', '' ), + changeset_revision=repository_error_dict.get( 'changeset_revision', '' ), + error_message=repository_error_dict.get( 'error_message', '' ) ) + subfolder.current_repository_installation_errors.append( repository_installation_error ) + installation_error_base_folder.folders.append( subfolder ) + if repository_dependency_errors: + folder_id += 1 + subfolder = Folder( id=folder_id, + key='repository_dependency_errors', + label='Repository dependencies', + parent=installation_error_base_folder ) + repository_error_id = 0 + for repository_error_dict in repository_dependency_errors: + repository_error_id += 1 + repository_installation_error = RepositoryInstallationError( id=repository_error_id, + tool_shed=repository_error_dict.get( 'tool_shed', '' ), + name=repository_error_dict.get( 'name', '' ), + owner=repository_error_dict.get( 'owner', '' ), + changeset_revision=repository_error_dict.get( 'changeset_revision', '' ), + error_message=repository_error_dict.get( 'error_message', '' ) ) + subfolder.repository_installation_errors.append( repository_installation_error ) + installation_error_base_folder.folders.append( subfolder ) + if tool_dependency_errors: + folder_id += 1 + subfolder = Folder( id=folder_id, + key='tool_dependency_errors', + label='Tool dependencies', + parent=installation_error_base_folder ) + tool_dependency_error_id = 0 + for tool_dependency_error_dict in tool_dependency_errors: + tool_dependency_error_id += 1 + tool_dependency_installation_error = ToolDependencyInstallationError( id=tool_dependency_error_id, + type=tool_dependency_error_dict.get( 'type', '' ), + name=tool_dependency_error_dict.get( 'name', '' ), + version=tool_dependency_error_dict.get( 'version', '' ), + error_message=tool_dependency_error_dict.get( 'error_message', '' ) ) + subfolder.tool_dependency_installation_errors.append( tool_dependency_installation_error ) + installation_error_base_folder.folders.append( subfolder ) + containing_folder.installation_errors.append( installation_error_base_folder ) + #containing_folder.folders.append( containing_folder ) + if multiple_tool_test_results_dicts: + tool_test_results_root_folder.folders.append( containing_folder ) else: tool_test_results_root_folder = None return folder_id, tool_test_results_root_folder @@ -1247,13 +1255,13 @@ workflows_root_folder = None return folder_id, workflows_root_folder -def can_display_tool_test_results( tool_test_results_dict, exclude=None ): +def can_display_tool_test_results( tool_test_results_dicts, exclude=None ): # Only create and populate the tool_test_results container if there are actual tool test results to display. if exclude is None: exclude = [] if 'tool_test_results' in exclude: return False - if tool_test_results_dict: + for tool_test_results_dict in tool_test_results_dicts: # We check for more than a single entry in the tool_test_results dictionary because it may have # only the "test_environment" entry, but we want at least 1 of "passed_tests", "failed_tests", # "installation_errors", "missing_test_components" "skipped_tests", "not_tested" or any other @@ -1288,7 +1296,7 @@ if key_is_current_repositorys_key( repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, key ): label = 'Repository dependencies' else: - if asbool( prior_installation_required ): + if galaxy.util.asbool( prior_installation_required ): prior_installation_required_str = " <i>(prior install required)</i>" else: prior_installation_required_str = "" @@ -1432,8 +1440,8 @@ repository_name=repository_name, repository_owner=repository_owner, changeset_revision=changeset_revision, - prior_installation_required=asbool( prior_installation_required ), - only_if_compiling_contained_td=asbool( only_if_compiling_contained_td ), + prior_installation_required=galaxy.util.asbool( prior_installation_required ), + only_if_compiling_contained_td=galaxy.util.asbool( only_if_compiling_contained_td ), installation_status=installation_status, tool_shed_repository_id=tool_shed_repository_id ) # Insert the repository_dependency into the folder. diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 test/install_and_test_tool_shed_repositories/functional_tests.py --- a/test/install_and_test_tool_shed_repositories/functional_tests.py +++ b/test/install_and_test_tool_shed_repositories/functional_tests.py @@ -58,7 +58,6 @@ from mercurial import __version__ from nose.plugins import Plugin from paste import httpserver -from time import strftime from tool_shed.util import tool_dependency_util from tool_shed.util.xml_util import parse_xml @@ -80,6 +79,12 @@ default_galaxy_test_host = '127.0.0.1' default_galaxy_master_api_key = None +# This script can be run in such a way that no Tool Shed database records should be changed. +if '-info_only' in sys.argv or 'GALAXY_INSTALL_TEST_INFO_ONLY' in os.environ: + can_update_tool_shed = False +else: + can_update_tool_shed = True + # Should this serve static resources (scripts, images, styles, etc.)? STATIC_ENABLED = True @@ -157,7 +162,7 @@ galaxy_tool_shed_url = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_SHED_URL', None ) tool_shed_api_key = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_SHED_API_KEY', None ) exclude_list_file = os.environ.get( 'GALAXY_INSTALL_TEST_EXCLUDE_REPOSITORIES', 'install_test_exclude.xml' ) - + if 'GALAXY_INSTALL_TEST_SECRET' not in os.environ: galaxy_encode_secret = 'changethisinproductiontoo' os.environ[ 'GALAXY_INSTALL_TEST_SECRET' ] = galaxy_encode_secret @@ -325,16 +330,16 @@ missing_tool_dependencies.extend( get_missing_tool_dependencies( repository_dependency ) ) return missing_tool_dependencies -def get_repository_info_from_api( url, repository_dict ): +def get_repository_dict( url, repository_dict ): error_message = '' parts = [ 'api', 'repositories', repository_dict[ 'repository_id' ] ] api_url = get_api_url( base=url, parts=parts ) extended_dict, error_message = json_from_url( api_url ) if error_message: return None, error_message - latest_changeset_revision, error_message = get_latest_downloadable_changeset_revision( url, - extended_dict[ 'name' ], - extended_dict[ 'owner' ] ) + name = str( extended_dict[ 'name' ] ) + owner = str( extended_dict[ 'owner' ] ) + latest_changeset_revision, error_message = get_latest_downloadable_changeset_revision( url, name, owner ) if error_message: return None, error_message extended_dict[ 'latest_revision' ] = str( latest_changeset_revision ) @@ -361,8 +366,9 @@ repository_dicts = [] params = urllib.urlencode( dict( do_not_test='false', downloadable='true', + includes_tools='true', malicious='false', - includes_tools='true', + missing_test_components='false', skip_tool_test='false' ) ) api_url = get_api_url( base=tool_shed_url, parts=[ 'repository_revisions' ], params=params ) baseline_repository_dicts, error_message = json_from_url( api_url ) @@ -372,7 +378,7 @@ for baseline_repository_dict in baseline_repository_dicts: # We need to get some details from the tool shed API, such as repository name and owner, to pass on to the # module that will generate the install methods. - repository_dict, error_message = get_repository_info_from_api( galaxy_tool_shed_url, baseline_repository_dict ) + repository_dict, error_message = get_repository_dict( galaxy_tool_shed_url, baseline_repository_dict ) if error_message: log.debug( 'Error getting additional details about repository %s from the API: %s' % ( str( name ), error_message ) ) else: @@ -447,16 +453,18 @@ tool_id = parts[ -2 ] return tool_id, tool_version -def get_tool_test_results_dict( tool_shed_url, encoded_repository_metadata_id ): +def get_tool_test_results_dicts( tool_shed_url, encoded_repository_metadata_id ): + """ + Return the list of dictionaries contained in the Tool Shed's repository_metadata.tool_test_results + column via the Tool Shed API. + """ error_message = '' api_path = [ 'api', 'repository_revisions', encoded_repository_metadata_id ] api_url = get_api_url( base=tool_shed_url, parts=api_path ) repository_metadata, error_message = json_from_url( api_url ) if error_message: return None, error_message - tool_test_results = repository_metadata.get( 'tool_test_results', {} ) - if tool_test_results is None: - return None, error_message + tool_test_results = repository_metadata.get( 'tool_test_results', [] ) return tool_test_results, error_message def get_webapp_global_conf(): @@ -466,7 +474,8 @@ global_conf.update( get_static_settings() ) return global_conf -def handle_missing_dependencies( app, repository, missing_tool_dependencies, repository_dict, tool_test_results_dict, results_dict ): +def handle_missing_dependencies( app, repository, missing_tool_dependencies, repository_dict, + tool_test_results_dicts, tool_test_results_dict, results_dict ): """Handle missing repository or tool dependencies for an installed repository.""" # If a tool dependency fails to install correctly, this should be considered an installation error, # and functional tests should be skipped, since the tool dependency needs to be correctly installed @@ -494,7 +503,8 @@ params = dict( tools_functionally_correct=False, do_not_test=False, test_install_error=True ) - register_test_result( galaxy_tool_shed_url, tool_test_results_dict, repository_dict, params ) + # TODO: do something usefule with response_dict + response_dict = register_test_result( galaxy_tool_shed_url, tool_test_results_dicts, tool_test_results_dict, repository_dict, params ) # Since this repository is missing components, we do not want to test it, so deactivate it or uninstall it. # The deactivate flag is set to True if the environment variable GALAXY_INSTALL_TEST_KEEP_TOOL_DEPENDENCIES # is set to 'true'. @@ -608,6 +618,13 @@ name = str( repository_dict[ 'name' ] ) owner = str( repository_dict[ 'owner' ] ) changeset_revision = str( repository_dict[ 'changeset_revision' ] ) + # Populate the tool_test_results_dict. + tool_test_results_dicts, error_message = get_tool_test_results_dicts( galaxy_tool_shed_url, encoded_repository_metadata_id ) + # The preparation script ~/tool_shed/scripts/check_repositories_for_functional_tests.py will have entered + # information in the 'test_environment' and possibly the 'missing_test_components' entries of the first + # tool_test_results_dict in the list of tool_test_results_dicts. We need to be careful to not lose this + # information. + tool_test_results_dict = tool_test_results_dicts.pop( 0 ) # See if this repository should be skipped for any reason. skip_this_repository = False skip_reason = None @@ -622,21 +639,20 @@ tool_test_results_dict[ 'not_tested' ] = dict( reason=skip_reason ) params = dict( tools_functionally_correct=False, do_not_test=False ) - register_test_result( galaxy_tool_shed_url, tool_test_results_dict, repository_dict, params ) + # TODO: do something usefule with response_dict + response_dict = register_test_result( galaxy_tool_shed_url, tool_test_results_dicts, tool_test_results_dict, repository_dict, params ) log.debug( "Not testing revision %s of repository %s owned by %s." % ( changeset_revision, name, owner ) ) else: - # Populate the tool_test_results_dict. - tool_test_results_dict, error_message = get_tool_test_results_dict( galaxy_tool_shed_url, encoded_repository_metadata_id ) if error_message: log.debug( error_message ) else: - # The preparation script ~/tool_shed/scripts/check_repositories_for_functional_tests.py will have entered - # information in the 'missing_test_components' entry of the tool_test_results_dict dictionary for repositories - # that are missing test components. We need to be careful to not lose this information. For all other repositories, - # no changes will have been made to this dictionary by the preparation script, and tool_test_results_dict will be None. - # Initialize the tool_test_results_dict dictionary with the information about the current test environment. test_environment_dict = tool_test_results_dict.get( 'test_environment', None ) test_environment_dict = get_test_environment( test_environment_dict ) + # Add the current time as the approximate time that this test run occurs. A similar value will also be + # set to the repository_metadata.time_last_tested column, but we also store it here because the Tool Shed + # may be configured to store multiple test run results, so each must be associated with a time stamp. + now = time.strftime( "%Y-%m-%d %H:%M:%S" ) + test_environment_dict[ 'time_tested' ] = now test_environment_dict[ 'galaxy_database_version' ] = get_database_version( app ) test_environment_dict[ 'galaxy_revision' ] = get_repository_current_revision( os.getcwd() ) tool_test_results_dict[ 'test_environment' ] = test_environment_dict @@ -662,8 +678,8 @@ params = dict( tools_functionally_correct=False, test_install_error=True, do_not_test=False ) - - register_test_result( galaxy_tool_shed_url, tool_test_results_dict, repository_dict, params ) + # TODO: do something usefule with response_dict + response_dict = register_test_result( galaxy_tool_shed_url, tool_test_results_dicts, tool_test_results_dict, repository_dict, params ) try: if deactivate: # We are deactivating this repository and all of its repository dependencies. @@ -697,6 +713,7 @@ repository, missing_tool_dependencies, repository_dict, + tool_test_results_dicts, tool_test_results_dict, results_dict ) else: @@ -705,7 +722,12 @@ file( galaxy_shed_tools_dict, 'w' ).write( to_json_string( shed_tools_dict ) ) log.debug( 'Saved generated shed_tools_dict to %s\nContents: %s' % ( str( galaxy_shed_tools_dict ), str( shed_tools_dict ) ) ) try: - results_dict = test_repository_tools( app, repository, repository_dict, tool_test_results_dict, results_dict ) + results_dict = test_repository_tools( app, + repository, + repository_dict, + tool_test_results_dicts, + tool_test_results_dict, + results_dict ) except Exception, e: exception_message = 'Error executing tests for repository %s: %s' % ( name, str( e ) ) log.exception( exception_message ) @@ -714,7 +736,12 @@ params = dict( tools_functionally_correct=False, do_not_test=False, test_install_error=False ) - register_test_result( galaxy_tool_shed_url, tool_test_results_dict, repository_dict, params ) + # TODO: do something usefule with response_dict + response_dict = register_test_result( galaxy_tool_shed_url, + tool_test_results_dicts, + tool_test_results_dict, + repository_dict, + params ) results_dict[ 'repositories_failed' ].append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) ) total_repositories_tested += 1 results_dict[ 'total_repositories_tested' ] = total_repositories_tested @@ -937,7 +964,7 @@ tool_data_path=additional_tool_data_path, shed_tool_data_table_config=None, persist=False ) - now = strftime( "%Y-%m-%d %H:%M:%S" ) + now = time.strftime( "%Y-%m-%d %H:%M:%S" ) print "####################################################################################" print "# %s - running repository installation and testing script." % now print "####################################################################################" @@ -949,12 +976,12 @@ repositories_passed = results_dict[ 'repositories_passed' ] repositories_failed = results_dict[ 'repositories_failed' ] repositories_failed_install = results_dict[ 'repositories_failed_install' ] - now = strftime( "%Y-%m-%d %H:%M:%S" ) + now = time.strftime( "%Y-%m-%d %H:%M:%S" ) print "####################################################################################" print "# %s - repository installation and testing script completed." % now print "# Repository revisions tested: %s" % str( total_repositories_tested ) - if '-info_only' in sys.argv: - print "# -info_only set, not updating the tool shed." + if not can_update_tool_shed: + print "# This run will not update the Tool Shed database." if total_repositories_tested > 0: if repositories_passed: print '# ----------------------------------------------------------------------------------' @@ -1048,26 +1075,26 @@ log.debug( 'Repository %s owned by %s, all revisions.' % ( str( name ), str( owner ) ) ) return exclude_list -def register_test_result( url, test_results_dict, repository_dict, params ): +def register_test_result( url, tool_test_results_dicts, tool_test_results_dict, repository_dict, params ): """ Update the repository metadata tool_test_results and appropriate flags using the Tool SHed API. This method updates tool_test_results with the relevant data, sets the do_not_test and tools_functionally correct flags to the appropriate values and updates the time_last_tested field to the value of the received time_tested. """ - if '-info_only' in sys.argv or 'GALAXY_INSTALL_TEST_INFO_ONLY' in os.environ: - return {} - else: + if can_update_tool_shed: metadata_revision_id = repository_dict.get( 'id', None ) if metadata_revision_id is not None: + tool_test_results_dicts.insert( 0, tool_test_results_dict ) + params[ 'tool_test_results' ] = tool_test_results_dicts # Set the time_last_tested entry so that the repository_metadata.time_last_tested will be set in the tool shed. - time_tested = datetime.utcnow() - test_results_dict[ 'time_last_tested' ] = time_ago( time_tested ) - params[ 'tool_test_results' ] = test_results_dict + params[ 'time_last_tested' ] = 'This entry will result in this value being set via the Tool Shed API.' url = '%s' % ( suc.url_join( galaxy_tool_shed_url,'api', 'repository_revisions', str( metadata_revision_id ) ) ) try: return update( tool_shed_api_key, url, params, return_formatted=False ) except Exception, e: log.exception( 'Error attempting to register test results: %s' % str( e ) ) + return {} + else: return {} def remove_generated_tests( app ): @@ -1138,7 +1165,7 @@ for repository in repositories_by_owner[ owner ]: print "# %s owned by %s, changeset revision %s" % ( repository[ 'name' ], repository[ 'owner' ], repository[ 'changeset_revision' ] ) -def test_repository_tools( app, repository, repository_dict, tool_test_results_dict, results_dict ): +def test_repository_tools( app, repository, repository_dict, tool_test_results_dicts, tool_test_results_dict, results_dict ): """Test tools contained in the received repository.""" name = str( repository.name ) owner = str( repository.owner ) @@ -1175,7 +1202,8 @@ params = dict( tools_functionally_correct=True, do_not_test=False, test_install_error=False ) - register_test_result( galaxy_tool_shed_url, tool_test_results_dict, repository_dict, params ) + # TODO: do something usefule with response_dict + response_dict = register_test_result( galaxy_tool_shed_url, tool_test_results_dicts, tool_test_results_dict, repository_dict, params ) log.debug( 'Revision %s of repository %s installed and passed functional tests.' % ( str( changeset_revision ), str( name ) ) ) else: tool_test_results_dict[ 'failed_tests' ].append( extract_log_data( result, from_tool_test=True ) ) @@ -1184,7 +1212,8 @@ params = dict( tools_functionally_correct=False, test_install_error=False, do_not_test=str( set_do_not_test ) ) - register_test_result( galaxy_tool_shed_url, tool_test_results_dict, repository_dict, params ) + # TODO: do something usefule with response_dict + response_dict = register_test_result( galaxy_tool_shed_url, tool_test_results_dicts, tool_test_results_dict, repository_dict, params ) log.debug( 'Revision %s of repository %s installed successfully but did not pass functional tests.' % \ ( str( changeset_revision ), str( name ) ) ) # Run the uninstall method. This removes tool functional test methods from the test_toolbox module and uninstalls the diff -r ad38b77e96fafc96060f9ee8031094f4a15df278 -r 11028b31d3f024ef920c3168d3f752bc13ba3ad8 tool_shed_wsgi.ini.sample --- a/tool_shed_wsgi.ini.sample +++ b/tool_shed_wsgi.ini.sample @@ -74,6 +74,9 @@ # path to sendmail sendmail_path = /usr/sbin/sendmail +# Number of saved tool test results produced by the install and test framework for each repository. +#num_tool_test_results_saved = 5 + # For use by email messages sent from the tool shed #smtp_server = smtp.your_tool_shed_server #email_from = your_tool_shed_email@server Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.